天下

记录修行的印记

C++类中模板函数的特化

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/

posted on 2013-06-26 11:51 天下 阅读(782) 评论(0)  编辑 收藏 引用 所属分类: C/C++C++模板


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2012年1月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

常用链接

留言簿(3)

随笔分类(369)

随笔档案(320)

链接

最新随笔

搜索

最新评论