私は自分のクラスを親クラスのテンプレートパラメータとして使用しています。その親クラスはテンプレート引数(ただしsizeof ())。子クラスを基本クラスのテンプレートパラメータとして、ネストされた名前指定子として使用する
そして、コンパイラは私に与える:
エラー:不完全型「の発動:: workerClass {別名のMyClass}」ネストされた名前指定
で使用されるしかしクラスがうまくファイルで定義されているが。基本クラスのインスタンス生成の時点で子クラスがインスタンス化されていないため、CRTPでそのようなことが起こり、問題はないからです。
私がテンプレート引数で子クラスを使用する理由は、子クラスが特定の関数を持っているか持っていない場合に、別の関数呼び出しを行うことです。
ここでエラーがラインで行わ
/* Structure similar to boost's enable if, to use
SFINAE */
template <int X=0, class U = void>
struct test {
typedef U type;
};
enum Commands {
Swim,
Fly
};
/* Structure used for template overloading,
as no partial function template specialization available */
template<Commands T>
struct Param {
};
template <class T>
class Invoker
{
public:
typedef T workerClass;
workerClass *wc() {
return static_cast<workerClass*>(this);
}
template <Commands command>
void invoke() {
invoke2(Param<command>());
}
/* If the child class has those functions, call them */
/* Needs template paramter Y to apply SFINAE */
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
invoke2(Param<Fly>) {
wc()->fly();
}
template<class Y=int>
typename test<sizeof(Y)+sizeof(decltype(&workerClass::swim))>::type
invoke2(Param<Swim>) {
wc()->shoot();
}
template<Commands command>
void invoke2(Param<command>) {
/* Default action */
printf("Default handler for command %d\n", command);
}
};
template <class T, class Inv = Invoker<T> >
class BaseClass : public Inv
{
public:
template<Commands command>
void invoke() {
Inv::template invoke<command>();
}
};
class MyClass : public BaseClass<MyClass>
{
public:
void swim() {
printf("Swimming like a fish!\n");
}
/* void fly(); */
};
void testing() {
MyClass foo;
foo.invoke<Fly>(); /* No 'void fly()' in MyClass, calls the default handler */
foo.invoke<Swim>(); /* Should print the swimming message */
}
をテストするための最小限のコードです:
typename test<sizeof(Y)+sizeof(decltype(&workerClass::fly))>::type
ので、これをサポートする任意のコンパイラがある、またはこれを明示的として標準で指定されたが、テンプレートの無効な使用ですか?私はこれをやっているやり方を変えなければならないのか、道を見つけなければならないのか? CRTPは、コードが有効であると私に期待していますが、わかりません。
これは本当に不可能な場合、なぜ正確に、そしてなぜCRTPが機能するのですか?
さて、問題は、少なくとも明確である:あなたは自己参照再帰的定義を作っている: 'BaseClassのは'ので 'decltypeの完全な' MyClass'が必要です'式ですが、' MyClass'は基本クラスとして完全な 'BaseClass 'を必要とします。 –
間接指定の追加層の背後にある特殊化を非表示にして、それらが基本クラス定義の一部として評価されないようにする必要があります。それらをプライベートネストされた型に入れて、すべて正常に動作します。 – ildjarn
CRTPは厳密にこのような理由から難題です。あなたが直面している問題は簡単に理解できます。基本テンプレートはクラス宣言の一部として、まだ完成していない時点でインスタンス化されます。ベーステンプレートが追加される可能性があります。そのため、コンパイラは、ベーステンプレートを最初に処理することなく、派生したタイプがどのようになるかを知ることができません。派生型の関数宣言の意味) –