哪个编译器是对的?需要模板化返回类型之前的“模板"?

2021-12-22 00:00:00 visual-c++ templates g++ c++ correctness

此代码段(摘自 this question) 用 g++ 编译得很好(如所见),只要返回类型之前的 template 就在那里.相比之下,VC10 不会编译该代码并出现以下错误:

This snippet (taken from this question) compiles fine with g++ (as seen), so long the template before the return type is there. In contrast, VC10 does not compile that code with the following error:

错误 C2244:'A::getAttr':无法将函数定义与现有声明相匹配

error C2244: 'A::getAttr' : unable to match function definition to an existing declaration

如果我删除 template,VC10 很高兴,但 g++ 会发出这个错误:

If I remove the template, VC10 is happy but g++ screams this error:

错误:用作模板的非模板AttributeType"
注意:使用'A::template AttributeType'表示是模板

error: non-template 'AttributeType' used as template
note: use 'A::template AttributeType' to indicate that it is a template

是不是又是因为VC的两阶段查找坏了还是什么原因?哪个编译器就在这里?我怀疑 g++ 是正确的,因为我对这里需要 template 有一个模糊的记忆,就像分配器内部的 rebind 模板一样.

Is it again because of VC's broken two-phase look-up or what is the cause? Which compiler is right here? I suspect g++ to be correct, as I have a vague memory of template being needed here, like with the rebind template inside of allocators.

编辑:我们有一个赢家:g++/GCC(惊喜...).

Edit: We have a winner: g++/GCC (surprise surprise...).

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 中提到:

GCC is right. AttributeType is a dependent template-name which is followed by angle bracket <, so the keyword template is required here to remove the ambiguity1, making it clear to the compiler that what is followed is a template-name. The rule is mentioned in §14.2/4:

当成员模板名称特化出现在 之后.或 ->在后缀表达式中,或之后嵌套名称说明符合格 ID,以及后缀表达式或限定 ID明确依赖于模板参数(14.6.2),成员模板名称必须加前缀通过关键字模板.否则假设名称命名为非模板.

When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

1 @Johannes 在这里写了一个很好的解释:

1 @Johannes has written a very good explanation here:

我必须将模板"放在哪里以及为什么要放?和类型名称"关键字?

相关文章