这个片段(取自这个问题)用g++编译得很好(如图所示),只要返回类型之前的template
存在。相反,VC10没有编译该代码,并出现以下错误:
错误C2244:"A::getAttr":无法将函数定义与现有声明匹配
如果我删除template
,VC10很高兴,但g++尖叫着这个错误:
错误:非模板"AttributeType"用作模板
注意:使用"A::template AttributeType"表示它是一个模板
这又是因为VC的两阶段查找失败还是原因?哪一个编译器就在这里?我怀疑g++是正确的,因为这里需要template
的模糊内存,就像分配器中的rebind
模板一样。
编辑:我们有一个赢家:g++/GCC(惊喜…)。
template <typename T, typename K>
class A {
public:
T t;
K k;
template <int i, int unused = 0>
struct AttributeType{
};
template <int i>
AttributeType<i> getAttr();
};
template <typename T, typename K>
template <int i>
typename A<T, K>::template AttributeType<i> A<T, K>::getAttr() {
// ^^^^^^^^ -- needed or not?
return t;
}
int main(){
A<int,int> a;
}
GCC是对的。AttributeType
是一个从属模板名称,后面跟有尖括号<
,因此这里需要关键字template
来消除歧义1,使编译器清楚地知道后面是一个模板名称。§14.2/4:中提到了该规则
当成员模板的名称专业化出现在之后。或->在后缀表达式中,或在中的嵌套名称说明符合格的id,以及后缀表达式或限定id显式依赖于模板参数(14.6.2)成员模板名称必须加前缀通过关键字模板。否则name被假定为非模板。
1@Johannes在这里写了一个非常好的解释:
我必须把";模板";以及";typename";关键词?