2009-03-16 5 views
50

私のプロジェクトのサブクラスのtypedefを使用しようとしていますが、私は以下の例で問題を切り分けました。不完全な型の無効な使用

誰かが間違っていると知っていますか?

template<typename Subclass> 
class A { 
    public: 
     //Why doesn't it like this? 
     void action(typename Subclass::mytype var) { 
      (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 

class B : public A<B> { 
    public: 
     typedef int mytype; 

     B() {} 

     void do_action(mytype var) { 
      // Do stuff 
     } 
}; 

int main(int argc, char** argv) { 
    B myInstance; 
    return 0; 
} 

これは私が得る出力されます:

[email protected]:~/Documents/LucadeStudios/experiments$ g++ -o test test.cpp 
test.cpp: In instantiation of ‘A<B>’: 
test.cpp:10: instantiated from here 
test.cpp:5: error: invalid use of incomplete type ‘class B’ 
test.cpp:10: error: forward declaration of ‘class B’ 

答えて

57

その理由は、クラステンプレートをインスタンス化、そのすべての宣言(ではありませんそのメンバ関数の定義もインスタンス化されます。特殊化の完全な定義が必要な場合は、クラステンプレートが正確にインスタンス化されます。これは、あなたの場合のように、例えばベースクラスとして使用される場合です。

は、だから何が起こるかは、その時点でBがまだ完了していないタイプである(それは、クラス定義の閉じ括弧の後で)A<B>

class B : public A<B> 

でインスタンス化されていることです。しかし、A<B>::actionの宣言は、それはそれの範囲にクロールされているので、完全であることをBが必要です。

Subclass::mytype 

あなたがする必要がどのようなBが完了した時に、いくつかのポイントにインスタンス化を遅らせています。これを行う1つの方法は、actionの宣言をメンバーテンプレートに変更することです。

template<typename T> 
void action(T var) { 
    (static_cast<Subclass*>(this))->do_action(var); 
} 

varが正しい型でない場合、do_actionvarを渡すと失敗するので、それはまだタイプセーフです。

+1

私は(私がここで説明しなかったいくつかの他の関連する問題のために)私のコードのわずかな再構成のために解決しましたが、私はこのアプローチをテストし、実際に問題を解決します。ありがとう! – seanhodges

0

あなたが適切なタイプは、コンパイラがそれをインスタンス化することはできません。この時点で知られていないとして、ポインタまたは参照を使用する必要があります。

void action(const typename Subclass::mytype &var) { 
      (static_cast<Subclass*>(this))->do_action(); 
    } 
+0

私はそれを参照とポインタに変更しようとしましたが、エラーは依然として同じです。私はあなたのポイントを理解する。 – seanhodges

2

あなたはA<B>からBを導き出し、それはクラスBの定義を見てたら、コンパイラは、ない最初の事はA<B>をインスタンス化しようとすることです:

代わりにしてみてください。これを行うには、actionのパラメータとしてB::mytypeが必要です。しかし、コンパイラは実際にBという実際の定義を把握しているだけなので、このタイプはまだ分かりませんし、エラーが発生します。この周り

一つの方法ではなく、派生クラスの内部で、別のテンプレートパラメータとしてパラメータの型を宣言することになります:

template<typename Subclass, typename Param> 
class A { 
    public: 
     void action(Param var) { 
       (static_cast<Subclass*>(this))->do_action(var); 
     } 
}; 

class B : public A<B, int> { ... }; 
1

ない、あなたが求めていた正確に何ができますが、アクションテンプレートのメンバ関数にすることができます。

template<typename Subclass> 
class A { 
    public: 
     //Why doesn't it like this? 
     template<class V> void action(V var) { 
       (static_cast<Subclass*>(this))->do_action(); 
     } 
}; 

class B : public A<B> { 
    public: 
     typedef int mytype; 

     B() {} 

     void do_action(mytype var) { 
       // Do stuff 
     } 
}; 

int main(int argc, char** argv) { 
    B myInstance; 
    return 0; 
} 
22

あなたは特性クラスを使用することによってこの問題を回避することができます
それはあなたがspecialsed特性クラスを設定する必要があなたが使用する各クラスのために

関連する問題