C++ 的巢狀類模板的特化定義不允許寫在類定義的範圍內
最近在使用在使用模板特化寫一段程式時發現一個奇怪的問題,比如像如下程式碼:
#include
<iostream> using namespace std; class CMyClass { public: template <typename T> struct test { T i; };
template <> int
main(void)
cout << "typeid(test1.i) is " <<
typeid(test1.i).name() <<
endl;
return 0; |
這段程式碼在Linux下的GCC 3.4.3下無法編譯通過,編譯時提示錯誤:
xxx.cpp:12: error: invalid explicit specialization before '>' token
xxx.cpp:12: error: explicit specialization in non-namespace scope `class CMyClass'
但在VC6和VC8下都可以編譯通過。
後翻閱資料,發現有人提到,C++標準中規定,巢狀類模板在類的定義中不允許被顯示特化宣告,只允許偏特化(“Explicit template specialization is forbidden for nested classes ”,“As partial template specialization is not forbidden ”),比如,這樣就可以:
#include
<iostream> class
CMyClass
cout << "typeid(test1.i) is " <<
typeid(test1.i).name() <<
endl; return 0; } |
在上面這段程式碼使用一個無用的模板引數來實現以偏特代替特化,從而化解了這個問題。至於為什麼VC下能夠正常編譯,網上的資料說是VC不符合標準(“MSVC is wrong in this case and g++ correct”),不過這點我尚未在C++標準中找到明文依據。
但是這樣一來就有個問題,偏特化在VC6下是用BUG的,無法正常使用,也就是說出來的程式碼將無法相容VC6。對於VC6這樣落伍的編譯器,相容它是沒有太大的必要,但是回頭想想,難道要在定義巢狀類模板的特化,就不行了麼?必須使用偏特化來代替麼?C++對此是如何規定的呢?翻閱相關資料後,我找到了答案--要把特化的程式碼寫在類定義的外面(要寫在namespace下),如第一段程式碼應該寫成這樣:
#include
<iostream> class CMyClass cout <<
"typeid(test1.i) is " << typeid(test1.i).name() <<
endl; return 0; |
這樣修改後,就可以在GCC下編譯通過了,同時,VC6,VC8也都能編譯通過!
總結一下吧:
在C++中,如果要對巢狀類模板進行特化,則要麼使用偏特化來替代特化(增加一個無用的模板引數),要麼將特化程式碼放在類定義之外。