2008-08-14 17 views
32

テンプレート引数に依存し、基本クラスのメンバを使用しますが、することはVisual Studioに行いますGCC問題:次のコードは、gccでコンパイルされません

template <typename T> class A { 
public: 
    T foo; 
}; 

template <typename T> class B: public A <T> { 
public: 
    void bar() { cout << foo << endl; } 
}; 

私はエラーを取得します

test.cpp: In member function ‘void B::bar()’:

test.cpp:11: error: ‘foo’ was not declared in this scope

しかし、それはすべきです!私は

void bar() { cout << this->foo << endl; } 

barを変更する場合、それコンパイルを行いますが、私はこれを行うには持っていないと思います。 C++の公式仕様には、GCCがここに従っているか、それともちょっと変わったことがありますか?

+0

[テンプレート化された派生クラスで、メンバー関数内で "this->"を使ってベースクラスメンバー名を修飾する必要があるのはなぜですか?](http://stackoverflow.com/questions/7908248/in-a-テンプレートベースの派生クラス - なぜ必要なのか - ベースクラスのメンバ名-w) – curiousguy

答えて

10

これはgcc-3.4に変更しました。このリリースでは、C++パーサーはより厳密になりましたが、レガシーまたはマルチプラットフォームのコードベースを持つ人にとってはまだまだ厄介なものです。

18

ワウ。 C++は奇妙なことで私を驚かせることは決してありません。狂気のちょうどすべての種類のです

In a template definition, unqualified names will no longer find members of a dependent base (as specified by [temp.dep]/3 in the C++ standard). For example,

template <typename T> struct B { 
    int m; 
    int n; 
    int f(); 
    int g(); 
}; 
int n; 
int g(); 
template <typename T> struct C : B<T> { 
    void h() 
    { 
    m = 0; // error 
    f(); // error 
    n = 0; // ::n is modified 
    g(); // ::g is called 
    } 
}; 

You must make the names dependent, e.g. by prefixing them with this->. Here is the corrected definition of C::h,

template <typename T> void C<T>::h() 
{ 
    this->m = 0; 
    this->f(); 
    this->n = 0 
    this->g(); 
} 

As an alternative solution (unfortunately not backwards compatible with GCC 3.3), you may use using declarations instead of this->:

template <typename T> struct C : B<T> { 
    using B<T>::m; 
    using B<T>::f; 
    using B<T>::n; 
    using B<T>::g; 
    void h() 
    { 
    m = 0; 
    f(); 
    n = 0; 
    g(); 
    } 
}; 

。ありがとう、ダビデ。

はここで、標準の "temp.dep/3" セクションの[ISO/IEC 14882:2003]:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [Example:

typedef double A; 
template<class T> class B { 
    typedef int A; 
}; 
template<class T> struct X : B<T> { 
    A a; // a has typedouble 
}; 

The type name A in the definition of X<T> binds to the typedef name defined in the global namespace scope, not to the typedef name defined in the base class B<T> . ] [Example:

struct A { 
    struct B { /* ... */ }; 
    int a; 
    int Y; 
}; 
int a; 
template<class T> struct Y : T { 
    struct B { /* ... */ }; 
    B b; //The B defined in Y 
    void f(int i) { a = i; } // ::a 
    Y* p; // Y<T> 
}; 
Y<A> ya; 

The members A::B , A::a , and A::Y of the template argument A do not affect the binding of names in Y<A> . ]

33

彼らはを参照していることDavid Joynerは歴史を持ちました、ここに理由があります。

B<T>をコンパイルするときの問題は、基本クラスA<T>がコンパイラからは不明であることです。これはテンプレートクラスであるため、コンパイラは基本クラスのメンバーを知ることができません。

以前のバージョンでは、実際には基本テンプレートクラスを解析することによって、いくつかの推論をしましたが、ISO C++は、この推論が存在してはならない紛争につながる可能と述べました。 gcc manual

template <typename T> class A { 
public: 
    T foo; 
}; 

template <typename T> class B: public A <T> { 
public: 
    void bar() { cout << A<T>::foo << endl; } 
}; 

詳細情報:

テンプレートで、基本クラスのメンバを参照するためのソリューションは、(あなたが行ったように)thisを使用するか、具体的基底クラスに名前を付けることです。 C++は、ここに何を負いかねます

+8

一方で、そのような意味があります。しかし一方で、それは本当に不自由な感じです。コンパイラは、テンプレートがインスタンス化されるまで 'foo'が何を参照するかを知る必要はありません。この時点で、' A'の 'foo'メンバを認識できるはずです。 C++には、これらの奇妙なコーナーケースが非常に多くあります。 –

+0

はい、これは全く受け入れられません...インスタンス化する前に知ることはできませんか?テンプレートの中でいつものようにインスタンス化を待ちます。それはそれの精神ですか? 何が混乱している... –

8

主な理由は、基本テンプレートは、後でタイプに特化することができるということです。継続的な元の例:

template<> 
class A<int> {}; 

B<int> x; 
x.bar();//this will fail because there is no member foo in A<int> 
3

VCではGCCは実行していませんが、2段階ルックアップは実装されていません。したがって、GCCはインスタンス化される前にテンプレートを解析し、VCよりも多くのエラーを検出します。 あなたの例では、fooは 'T'に依存するので、従属名です。コンパイラがどこから来たのかをコンパイラに伝えない限り、インスタンス化する前にテンプレートの有効性を確認することはできません。 その理由は、コンパイラの出所をコンパイラに伝える必要があるからです。

関連する問題