5
template<typename T> struct A {
    auto func() -> decltype(T::func()) {
        return T::func();
    }
};
class B : public A<B> {
    void func() {
    }
};

私にはかなり単純なようです。しかし、MSVCはコンパイルに失敗します。

visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'func' : is not a member of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see declaration of 'B'
visual studio 2010\projects\temp\temp\main.cpp(8) : see reference to class template instantiation 'A<T>' being compiled
          with
          [
              T=B
          ]
visual studio 2010\projects\temp\temp\main.cpp(4): error C3861: 'func': identifier not found

コンパイラーは関数の呼び出しを喜んで受け入れますが。以下のサンプルは正常にコンパイルされます。

template<typename T> struct A {
    void func() {
        return T::func();
    }
};
class B : public A<B> {
    void func() {
    }
};

テンプレート引数から任意の型を使用しようとすると、同じ問題が発生します。

template<typename T> struct A {
    typedef typename T::something something;
};
class B : public A<B> {
    typedef char something;
};

visual studio 2010\projects\temp\temp\main.cpp(4): error C2039: 'something' : is not a member of 'B'

一方、クラスBは「何か」と呼ばれるタイプを明確に定義しています。コンパイラーは、T型、T&型、またはT *型のオブジェクトで関数を呼び出すことができますが、Tからどの型にもアクセスできないようです。

4

3 に答える 3

3

T::func宣言される前に使用しようとしています。そのため、コンパイラはあなたに向かって叫びます。クラスから派生する場合、クラステンプレートから派生している場合は、クラスが生成されることに注意してください。また、クラスの暗黙的な生成(暗黙的なインスタンス化と呼ばれます)では、そのすべてのメンバーの宣言を生成する必要があります(したがって、コンパイラーはクラスのsizeof値を認識し、クラスのルックアップを実行できます)。

したがって、宣言もインスタンス化され、auto func() -> decltype(T::func())ここでは確実に失敗します。

于 2010-11-21T11:59:15.780 に答える
2

コードにいくつかの問題があるようですが、そのうちの1つはVS10のバグのようです。

  1. にキャストせずにT::func()から呼び出しています。から派生していないため、これはCRTPの一部として必要です。--FixLAATATreturn static_cast<T*>(this)->func();
  2. 渡すものは、実際にはインスタンス関数であるのdecltypeに対し、静的関数呼び出しのように見えます。実際には関数を実行しないfuncので、次のようにする必要がありますdecltype decltype(static_cast<T*>(nullptr)->func())
  3. funcはプライベートでBあり、から呼び出すことはできませんA-修正:に変更Aしてstruct
  4. BこれはVS10のバグのように見えますが、これらすべての修正を行った後でも、で未定義のクラスを使用しようとしているというエラーが発生しますdecltype

func回避策として、基本クラスにリファクタリングできますか?(ここで、2つのテンプレートパラメーターが必要です。1つはキャスト先用で、もう1つdecltypeは新しいイディオムCRTPEXを作成するためのものです)

struct Base { 
    void func() { }
};

template<typename T, typename U> struct A {
    auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
        return static_cast<U*>(this)->func();
    }
};


struct B : public A<Base, B>, public Base {
};

g ++もこれを窒息させてdecltypeいるようですが、これが欠陥であることを誰かが確認できますか?もしそうなら、私はマイクロソフトのバグを開きます。次のコードは有効ですが、g++もVC10もコンパイルしないことを理解しています。

template<typename T> struct A {
    auto func() -> decltype(static_cast<T*>(nullptr)->func()) {
        return static_cast<T*>(this)->func();
    }
};

struct B : public A<B> {
    void func() {}
};
于 2010-11-21T09:22:40.940 に答える
1

まず、適切に近いコードは次のとおりだと思います。

template<typename T> struct A {
    auto func()
     -> decltype(static_cast<T*>(this)->func()) 
    {
        return static_cast<T*>(this)->func();
    }
};
class B : public A<B> {
    void func(){
    }
};

モッティが指摘したように。しかし、それでも失敗し、ベースのリターンタイプをいつB継承するかを知る必要があると思いますA<B>が、Bまだ定義されていないため、鶏と卵の問題になります。

ただ、 (なしで)C++1y使うだけでやっと可能かもしれませんが、使ってみましたautodecltypegcc-4.8.2

template<typename T> struct A {
    auto func()
    //c++1y// -> decltype(static_cast<T*>(this)->func()) 
    {
        return static_cast<T*>(this)->func();
    }
};
class B : public A<B> {
    void func(){
    }
};

c++ -std=c++1yこれは( )をコンパイルして実行します:

int main(){
  B b; b.func();
}

2つの免責事項:これが機能する理由がわかりません。それがどれほど標準的かはわかりません。

于 2013-11-02T05:37:00.457 に答える