About
RSS

Bit Focus


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

Posted at 2013-01-14 03:26:03 | Updated at 2018-02-21 23:22:21

    用 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 template
    A<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;
}

Post tags:   C++  Template

Leave a comment:




Creative Commons License Your comment will be licensed under
CC-NC-ND 3.0


. Back to Bit Focus
NijiPress - Copyright (C) Neuron Teckid @ Bit Focus
About this site