clang++ - 在类作用域中将模板类名称视为模板

4

看起来clang++(我尝试了clang 3.2)将模板类名称视为已实例化的类,而不是在类作用域内的任何出现的模板。例如,以下代码:

template <template <class> class T>
class A {};

template <typename T>
class B {
    A<B> member;
   // ^---- clang++ treats B as an instantiated class
         // but I want it to be a template here
         // this code could compile in g++
};

int main()
{
    B<int> b;
    return 0;
}

我该怎么做才能编译它?

2个回答

3

C++03

通过这种方式(称为注入类名,是每个类(包括模板实例化)的隐式声明成员)解析B旨在提供便利。我从未见过它会妨碍什么!

要解决此问题,请在名称前添加“::”(如果必要,还要加上命名空间的名称)来限定名称。

template <typename T>
class B {
    A< ::B> member; // whitespace required to prevent digraph; see comments
};

C++11

根据C++11 §14.6.1/1规定(重点标记为粗体):

像普通(非模板)类一样,类模板有一个注入的类名(第9条)。注入的类名可以用作模板名或类型名。当它与模板参数列表一起用作模板模板参数的模板参数,或者用作友元类模板声明中详细说明类型的最后一个标识符时,它指的是类模板本身。否则,它等同于跟随在<>中的类模板的模板名和模板参数。

因此,如果在C++11下出现此问题,则是编译器错误。按照上述方法进行解决。

请注意 - 相比之下,C++03中的相应段落如下:

像普通(非模板)类一样,类模板有一个注入的类名(第9条)。注入的类名可以带或不带模板参数列表。当它不带模板参数列表时,它等同于跟在注入的类名后面的类模板的模板参数<>括号内。当它带有模板参数列表时,它引用指定的类模板特化,该特化可以是当前特化或另一个特化。

正如您所看到的,已经有一种特殊情况允许标识符成为类或模板,具体取决于它是否出现在模板名中。他们只是添加了几个更多的情况。


@neuront:哇...从来不知道 <: ...给你们两个加1分 - Cornstalks
1
@Cornstalks,如果你感兴趣的话,这是一个有向图,对于那些过去没有 [ 键的人来说。 - chris
@neuront <:: 是词法分析器的一个特例,但它是C++11中的新功能。 - Potatoswatter
你关于C++11允许在字符之间不加空格的评论很有趣。请看我的回答以获取解释 :-) - Johannes Schaub - litb

1

这是不符合C++11标准的行为,因为C++11规定,当注入类名(即在类体内自动声明的名称)传递给模板模板参数时,它是一个模板。因此,您的代码应该只在C++03实现中失败。

然而,现在没有必要再报告这个错误了。我早就已经做过了。


然而现在没有必要报告这个错误。我早就已经处理好了。这很典型的litb,是吧 :-) - Alok Save

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接