C++奇怪的编译器语法错误

C++ Strange Compiler Syntax Error

本文关键字:语法 错误 编译器 C++      更新时间:2023-10-16

我得到了以下代码(不要争论它是否有意义,它只是一个最小的例子):

struct X{
    template <typename T>
    T foo(){ return T(); }
};
template <typename T>
struct Z{
    virtual X bar(){
        bar().foo<int>();
        return X();
    }
};

它没有在我的g++4.6.3上编译。线路bar().foo<int>();给出以下错误:

error: expected primary-expression before ‘int’
error: expected ‘;’ before ‘int’

当我第一次将bar()的结果保存在本地变量中时,它就起作用了,即如果我用替换bar().foo<int>()

        X x = bar();
        x.foo<int>(); 

那么它就起作用了。如果我现在声明局部变量auto而不是X,即:

        auto x = bar();
        x.foo<int>();

那么我会收到与以前相同的错误。如果我从类Z中删除了类型参数(即使其成为普通类而不是模板类),那么它就会再次工作。

如果我使用类似X的类类型而不是int作为foo的类型参数,即foo<X>,那么我会收到以下错误:

expected primary-expression before ‘>’ token
expected primary-expression before ‘)’ token

我真的无法发现这里的错误。请帮忙!

您需要确认所讨论的类型是可模板的(这是针对我认为GCC中的一个错误的解决方案,请参阅下面的编辑),即

struct X{
    template <typename T>
    T foo(){ return T(); }
};
template <typename T>
struct Z{
    virtual X bar(){
        bar().template foo<int>();
        return X();
    }
};

基本问题与解析有关,因为显式模板实例化可以通过多种方式进行解析。有趣的比特(我认为)位于14.2p4,如下所示:

当成员模板专用化的名称出现在后缀表达式中的.->之后,或出现在限定id中的嵌套名称指定器,以及后置表达式的对象或指针表达式限定id中的嵌套名称指定器依赖于模板参数(14.6.2),但不引用当前实例化的成员(14.6.2.1),成员模板名称必须由关键字template预先固定。否则,该名称将被假定为命名非模板。

如果我没有严重错误的话,Z<T>::bar确实依赖于模板参数,但同时它确实引用了当前的实例化,因此我倾向于相信该标准不需要像GCC那样的资格。当多个编译器有冲突的结果时,我倾向于支持Comeau,在这种情况下,它说template限定符是,而不是必需的