2

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

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而不是intfoo 的类型参数 ie foo<X>,那么我会收到以下错误:

expected primary-expression before ‘&gt;’ token
expected primary-expression before ‘)’ token

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

4

1 回答 1

8

您需要确定所讨论的类型是可模板化的(这是我认为是 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,如下所示:

当成员模板特化的名称出现在后缀表达式之后或之后,或者在 qualified-id 中的 .嵌套名称说明符之后,并且后缀表达式嵌套名称说明符的对象或指针表达式出现在qualified-id依赖于模板参数 (14.6.2) 但不引用当前实例化的成员 (14.6.2.1),成员模板名称必须以关键字 为前缀。否则,该名称被假定为命名非模板。->template

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

于 2012-09-03T18:26:06.800 回答