在 C++ 模板类体中将类名仍视为模板

用 Clang++ 编译下面的源代码 (已测试 ArchLinux clang 3.2-3)

template <template <class> class T>class A {};template <typename T>class B {A<B> member;};int main(){B<int> b;return 0;}会得到如下错误信息

error: template argument for template template parameter must be a class templateA<B> member;^也就是说, clang++ 会认为出现在模板类 B 的类体中的符号 B 是一个已经实例化过的类型, 不能够被传递给模板类 A 用于实例化.而 g++ 4.7 可以正确编译通过, 说明 g++ 肯定内置了某种脑补机制, 能灵活处理这样的情况, 它甚至可以编译如下分裂的代码

template <template <class> class T>class A {};template <class T>class C {};template <typename T>class B {A<B> member;C<B> another;};int main(){B<int> b;return 0;}当然在 clang++ 下也不是没办法解决了, 方案是, 在类体中如果要将类名当作模板来使用, 则在名字前加上名字空间声明. 如上面 B 定义在全局名字空间中, 所以代码应该这样修改

template <template <class> class T>class A {};template <typename T>class B {A< ::B> member;};int main(){B<int> b;return 0;}话说小于号跟双冒号之间有个空格 < ::, 这绝不是我手残了抖上去的, 而是这地方必须要一个空格. C++ 程序设计领域流行着各种都市传说, 其中有模板套模板结束时的两个大于号之间要加个空格什么的, 类似, 小于号跟冒号之间也要加个空格, 否则 <: 会被认为是 [.相应地, 如果 B 定义于某个有名字的名字空间 (这话说得…) 中那么上面代码应作相应修改

template <template <class> class T>class A {};namespace ns {template <typename T>class B {A<ns::B> member;};}int main(){ns::B<int> b;return 0;}

在 C++ 模板类体中将类名仍视为模板

相关文章:

你感兴趣的文章:

标签云: