C++類中模板函數的特化
最近在使用在使用模板特化 寫一段程序時發現一個奇怪的問題,比如像如下代碼:
#include <iostream>
using namespace std;
class CMyClass
{
public:
template <typename T>
struct test
{
T i;
};
template <>
struct test<long>
{
unsigned long i;
};
};
int main(void)
{
CMyClass::test<int> test1;
CMyClass::test<long> test2;
CMyClass::test<char> test3;
cout << "typeid(test1.i) is " << typeid(test1.i).name() << endl;
cout << "typeid(test2.i) is " << typeid(test2.i).name() << endl;
cout << "typeid(test3.i) is " << typeid(test3.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>
using namespace std;
class CMyClass
{
public:
template <typename T, typename S = void>
struct test
{
T i;
};
template <typename S>
struct test<long, S>
{
unsigned long i;
};
};
int main(void)
{
CMyClass::test<int> test1;
CMyClass::test<long> test2;
CMyClass::test<char> test3;
cout << "typeid(test1.i) is " << typeid(test1.i).name() << endl;
cout << "typeid(test2.i) is " << typeid(test2.i).name() << endl;
cout << "typeid(test3.i) is " << typeid(test3.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>
using namespace std;
class CMyClass
{
public:
template <typename T>
struct test
{
int i;
};
};
template <>
struct CMyClass::test<long>
{
long i;
};
int main(void)
{
CMyClass::test<int> test1;
CMyClass::test<long> test2;
CMyClass::test<char> test3;
cout << "typeid(test1.i) is " << typeid(test1.i).name() << endl;
cout << "typeid(test2.i) is " << typeid(test2.i).name() << endl;
cout << "typeid(test3.i) is " << typeid(test3.i).name() << endl;
return 0;
}
這樣修改后,就可以在GCC下編譯通過了,同時,VC6,VC8也都能編譯通過!
總結一下吧:
在C++中,如果要對嵌套類模板進行特化,則要么使用偏特化來替代特化(增加一個無用的模板參數),要么將 特化代碼放在類定義之外。
同樣的,非模板函數具有最高的優先權
轉自:
http://jeffreyloo.blog.163.com/blog/static/12176167020106171424608/