C++ 的嵌套类模板的特化定义不允许写在类定义的范围内
2014-07-24 17:57
302 查看
最近在使用在使用模板特化写一段程序时发现一个奇怪的问题,比如像如下代码:
这段代码在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 ”),比如,这样就可以:
在上面这段代码使用一个无用的模板参数来实现以偏特代替特化,从而化解了这个问题。至于为什么VC下能够正常编译,网上的资料说是VC不符合标准(“MSVC is wrong in this case and g++ correct”),不过这点我尚未在C++标准中找到明文依据。
但是这样一来就有个问题,偏特化在VC6下是用BUG的,无法正常使用,也就是说出来的代码将无法兼容VC6。对于VC6这样落伍的编译器,兼容它是没有太大的必要,但是回头想想,难道要在定义嵌套类模板的特化,就不行了么?必须使用偏特化来代替么?C++对此是如何规定的呢?翻阅相关资料后,我找到了答案--要把特化的代码写在类定义的外面(要写在namespace下),如第一段代码应该写成这样:
这样修改后,就可以在GCC下编译通过了,同时,VC6,VC8也都能编译通过!
总结一下吧:
在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; } |
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; } |
但是这样一来就有个问题,偏特化在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; } |
总结一下吧:
在C++中,如果要对嵌套类模板进行特化,则要么使用偏特化来替代特化(增加一个无用的模板参数),要么将特化代码放在类定义之外。
相关文章推荐
- C++ 函数模板特化导致的多重定义链接错误
- C++ 函数模板特化导致的多重定义链接错误
- C++模板应用——在类模板实现中引用其内部定义的复合数据类型
- C++ 之 模板与泛型编程(一、模板定义)
- 用汇编的眼光看C++(之缺省模板、特化模板)
- c++模板与泛型编程(一)模板定义 ——《c++ primer》读书笔记
- 编译器定义的C/C++语言各种基本数据类型的取值范围
- C++ 模板的偏特化
- C++模板声明定义分离编译错误详解
- 【C++模板】特化与偏特化 template [partial] specialization
- C++模板应用——让模板定义和实现分离的方法
- C++ Standard Stl -- SGI STL源码学习笔记(03) STL中的模板编译期检查与偏特化编译期检查
- C++模板用法:定义、使用 示例
- C++模板中type_traits(类型特化)
- C++模板的特化
- 【C++模板】特化与偏特化 template [partial] specialization
- c++模板的定义和实现
- C++模板与定义分离
- 用汇编的眼光看C++(之缺省模板、特化模板)
- C++的模板特化及STL中iterator_traits模板的偏特化