8

コンパイルするコードのセクションを含む大規模なプロジェクトに取り組んでいますが、その方法がわかりません。私はそれを次の簡単な例に絞り込みました。

template <typename T>
struct First {
    typedef int type;           // (A)
    typename T::Three order;    // (B)
};

template <typename T> struct Second {
    typedef typename T::type type;
};


template <typename T> struct Third {
    int val;
    T two;
};

struct Traits {
    typedef First<Traits> One;
    typedef Second<One> Two;
    typedef Third<Two> Three;
};

int main(int argc, char** argv) {
    Traits::One x;
};

クラスFirstはテンプレート化されてTraitsおりTraits::Three、それ自体がtypedefベースでTwoあり、typedefベースであるFirst<Traits>...を参照しているため、循環しています。しかし、このコードは gcc4.6 と VC10 の両方で正常にコンパイルされます。ただし、 と でマークされた 2 行の順序を逆にする(A)と、コードはコンパイルされず、 の内部(B)について不平を言います。typedefSecond

このコードがコンパイルされるのはなぜtypedefですか? また、 とメンバー変数の順序が重要なのはなぜですか?

4

3 に答える 3

3

言う価値のあることがいくつかあります。

  • Secondを含むように変更すると、コードが壊れます。

    T badObject;
    

    長い「インスタンス化された...」チェーンで「不完全な型」エラーで終了します。これは、期待する循環性によるものですが、代わりに追加した場合はそうではありません

    typename T::type object;
    

    これは、コンパイラがを完全にカプセル化する必要はなくT、何が何であるかを知るためだけに巧妙に観察していることを示していT::typeます。これを説明するために、合法的に持つことができることに注意してください

    First { ... typedef T type; ... }
    Second { typename T::type object; }
    

    T には現在定義されているオブジェクトが含まれていないため、または

    First { ... typedef typename T::One type; ... }
    Second { typedef typename T::type object; }
    

    typedefinSecondはいずれのオブジェクトのインスタンスも必要としないため - ただしたとえば、

    First { ... typedef typename T::One type; ... }
    Second { typename T::type object; }
    

    その場合にのみ、コンパイラは実際にFirst<Traits>オブジェクト内にオブジェクトをネストする必要がありFirst<Traits>ます。

  • (A) と (B) を交換する際の問題は、上記のコンパイラーが引き出した巧妙なトリックが、各特殊化されたテンプレートの定義の新しいコピーを導入し、一度に1 行ずつ解析することによって機能していることです。Firstによってタイプ定義を知る必要があるときに、タイプ定義まで到達していない場合、エラーが発生しSecondます。

于 2013-04-10T20:55:48.803 に答える
1

の完全な型は必要ありませんtypedef

于 2013-04-10T20:16:23.347 に答える