C++類中模板函數(shù)的特化
最近在使用在使用模板特化 寫一段程序時(shí)發(fā)現(xiàn)一個(gè)奇怪的問題,比如像如下代碼:
#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下無法編譯通過,編譯時(shí)提示錯(cuò)誤:
xxx.cpp:12: error: invalid explicit specialization before '>' token
xxx.cpp:12: error: explicit specialization in non-namespace scope `class CMyClass'
但在VC6和VC8下都可以編譯通過。
后翻閱資料,發(fā)現(xiàn)有人提到,C++標(biāo)準(zhǔn)中規(guī)定,嵌套類模板在類的定義中不允許被顯示特化聲明,只允許偏特化(“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;
}
在上面這段代碼使用一個(gè)無用的模板參數(shù)來實(shí)現(xiàn)以偏特代替特化,從而化解了這個(gè)問題。至于為什么VC下能夠正常編譯,網(wǎng)上的資料說是VC不符合標(biāo)準(zhǔn) (“MSVC is wrong in this case and g++ correct”),不過這點(diǎn)我尚未在C++標(biāo)準(zhǔn)中找到明文依據(jù)。
但是這樣一來就有個(gè)問題,偏特化在VC6下是用BUG的,無法正常使用,也就是說出來的代碼將無法兼容VC6。對(duì)于VC6這樣落伍的編譯器,兼容它 是沒有太大的必要,但是回頭想想,難道要在定義嵌套類模板的特化,就不行了么?必須使用偏特化來代替么?C++對(duì)此是如何規(guī)定的呢?翻閱相關(guān)資料后,我找 到了答案--要把特化的代碼寫在類定義的外面(要寫在namespace下),如第一段代碼應(yīng)該寫成這樣:
#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下編譯通過了,同時(shí),VC6,VC8也都能編譯通過!
總結(jié)一下吧:
在C++中,如果要對(duì)嵌套類模板進(jìn)行特化,則要么使用偏特化來替代特化(增加一個(gè)無用的模板參數(shù)),要么將 特化代碼放在類定義之外。
同樣的,非模板函數(shù)具有最高的優(yōu)先權(quán)
轉(zhuǎn)自:
http://jeffreyloo.blog.163.com/blog/static/12176167020106171424608/