當類別擁有私有解構函式(或其他私有成員),外部函式模板(如 boost::checked_delete)無法存取。解決方案是將該模板特化宣告為友元。C++ 標準提供兩種合法語法,但編譯器支援度參差不齊。
namespace boost {
template<typename T> void checked_delete(T* x) { delete x; }
}
class Test {
~Test() {} // 私有解構函式
// 語法 #3 形式(簡化版,依賴名稱查找規則)
friend void boost::checked_delete(Test* x);
// 語法 #1 形式(明確指定模板參數,推薦)
friend void boost::checked_delete<Test>(Test* x);
// 或等價的
friend void boost::checked_delete<>(Test* x);
};
boost::)會劇烈改變語意(落入規則 #4,宣告非模板函式),極不直覺。| 編譯器 | 語法 #3 | 語法 #1 |
|---|---|---|
| GCC | ❌ | ❌ |
| MSVC 6.0 | ❌ | ❌ |
| MSVC 7.1+ | ❌ | ✅ |
| Borland | ✅ | ✅ |
| EDG / Comeau / Intel | ✅ | ✅ |
| Metrowerks | ❌ | ✅ |
using boost::checked_delete;
class Test {
friend void checked_delete(Test* x); // 落入規則 #4,宣告全域非模板函式 ::checked_delete
};
導致連結錯誤(找不到定義)且無法存取私有成員。
using boost::checked_delete;
friend void checked_delete<>(Test* x); // 非合法 C++,標準未定義,所有測試編譯器拒絕
namespace boost {
template<typename T> void checked_delete(T* x);
}
class Test {
// ❌ 不好:依賴晦澀規則,移植性差
friend void boost::checked_delete(Test* x);
// ✅ 好:明確指定模板參數,語意清晰,移植性佳
friend void boost::checked_delete<>(Test* x);
// 或
friend void boost::checked_delete<Test>(Test* x);
};
原則:Say what you mean, be explicit. 永遠明確標註 <> 或 <Type>。
若編譯器不支援上述語法,唯一選擇是將成員宣告為 public,並加註解說明:
// TODO: 編譯器升級後改回 private + friend template
public:
~Test() {}
模板友元化看似簡單,實則暗藏標準細節與編譯器差異。堅持使用明確特化語法(<> 或 <Type>),能最大化程式碼移植性與可維護性。