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からtypeパラメーターを削除すると(つまり、テンプレートクラスではなく通常のクラスにする)、再び機能します。

fooのタイプパラメータとしてXではなくのようなクラスタイプを使用すると、代わりに次のエラーが発生します。intfoo<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にあり、次のとおりです。

メンバーテンプレートの特殊化の名前が、後置式の後または後、または修飾ID内のネストされた名前指定子の後に表示.->置式または ネストた名前指定子のオブジェクトまたはポインター式がqualified -idはテンプレートパラメーター(14.6.2)に依存しますが、現在のインスタンス化(14.6.2.1)のメンバーを参照しないため、メンバーテンプレート名の前にキーワードを付ける必要があります。それ以外の場合、その名前は非テンプレートの名前であると見なされます。template

私が重大な誤りを犯していない場合Z<T>::bar テンプレートパラメータに依存しますが、同時に現在のインスタンス化を参照しているため、GCCのように標準が修飾を必要としないと信じる傾向があります。複数のコンパイラの結果が競合する場合、私はComeauを支持する傾向があります。この場合、template修飾子は必要ありません

于 2012-09-03T18:26:06.800 に答える