98

我一直在玩 clang,我偶然发现了“test/SemaTemplate/dependent-template-recover.cpp”(在 clang 发行版中),它应该提供从模板错误中恢复的提示。

整个事情可以很容易地简化为一个最小的例子:

template<typename T, typename U, int N> struct X {
    void f(T* t)
    {
        // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
        t->f0<U>();
    }
};

clang 产生的错误信息:

tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
         t->f0<U>();
            ^
            template 
1 error generated.

...但是我很难理解应该在哪里插入template关键字以使代码在语法上正确?

4

4 回答 4

117

ISO C++03 14.2/4:

当成员模板专业化的名称出现在 . 或 -> 在后缀表达式中,或在限定标识中的嵌套名称说明符之后,并且后缀表达式或限定标识显式依赖于模板参数(14.6.2),成员模板名称必须是以关键字 template 为前缀。否则,该名称被假定为命名非模板。

Int->f0<U>(); f0<U>是一个成员模板特化,它出现在模板参数之后->并且显式依赖于模板参数U,因此成员模板特化必须以template关键字为前缀。

所以t->f0<U>()改为t->template f0<U>().

于 2010-09-24T11:14:49.927 回答
26

除了其他人提出的观点之外,请注意有时编译器无法下定决心,并且两种解释都可以在实例化时产生替代的有效程序

#include <iostream>

template<typename T>
struct A {
  typedef int R();

  template<typename U>
  static U *f(int) { 
    return 0; 
  }

  static int f() { 
    return 0;
  }
};

template<typename T>
bool g() {
  A<T> a;
  return !(typename A<T>::R*)a.f<int()>(0);
}


int main() {
  std::cout << g<void>() << std::endl;
}

这会在之前0省略但插入时打印。我把它作为一个练习来弄清楚代码的作用。templatef<int()>1

于 2010-09-24T11:46:12.240 回答
14

将它插入到插入符号所在的点之前:

template<typename T, typename U, int N> struct X {
     void f(T* t)
     {
        t->template f0<U>();
     }
};

编辑:如果你像编译器一样思考,这条规则的原因会变得更清楚。编译器通常一次只向前看一两个标记,并且一般不会“向前看”到表达式的其余部分。[编辑:见评论] 关键字的原因与您需要typename关键字来指示依赖类型名称的原因相同:它告诉编译器“嘿,您即将看到的标识符是模板的名称,而不是静态数据成员的名称,后跟一个小于号”。

于 2010-09-24T11:01:24.373 回答
12

摘自C++ 模板

.template 构造在引入 typename 后发现了一个非常相似的问题。考虑以下使用标准位集类型的示例:

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
                                       allocator<char> >(); 
} 

这个例子中奇怪的结构是 .template。如果没有额外使用模板,编译器不知道后面的小于标记 (<) 并不是真正的“小于”,而是模板参数列表的开头。请注意,仅当句点之前的构造依赖于模板参数时,这才是问题。在我们的示例中,参数 bs 取决于模板参数 N。

总之,.template 表示法(和类似的表示法,例如 ->template)应该只在模板内部使用,并且只有当它们遵循依赖于模板参数的东西时。

于 2010-09-24T11:11:58.873 回答