C++静的多相性(CRTP)と派生クラスからの型定義使用について
質問
私は ウィキペディアの記事 を読んで、C++ で不思議なことに繰り返されるテンプレートパターンで静的な(コンパイル時の)ポリモーフィズムを実現することを知りました。私はこれを一般化して、関数の戻り値の型を派生型に基づいて変更できるようにしたいと思いました。(基本型はテンプレート・パラメータから派生型を知っているので、これは可能なはずです)。残念ながら、以下のコードはMSVC 2010でコンパイルできません(今、gccに簡単にアクセスできないので、まだ試していません)。どなたか理由をご存知ですか?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
ところで、私は余分なテンプレートパラメータを使用して回避策を持っていますが、私はそれが好きではありません---それは、継承チェーンの上に多くの型を渡すときに非常に冗長になります。
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public base<derived<T>,T> { ... };
EDITです。
このような状況でMSVC2010が出すエラーメッセージは
error C2039: 'value_type' : is not a member of 'derived<T>'
g++ 4.1.2 (via
codepad.org
) によると
error: no type named 'value_type' in 'class derived<int>'
どのように解決するのですか?
derived
のテンプレート引数として使用する場合、不完全です。
base
へのテンプレート引数として使用すると、不完全です。
一般的な回避策は traits クラスのテンプレートを使用することです。 以下は、traits化したあなたの例です。 これは、派生クラスから型と関数の両方をtraitを通して使用する方法を示しています。
// Declare a base_traits traits class template:
template <typename derived_t>
struct base_traits;
// Define the base class that uses the traits:
template <typename derived_t>
struct base {
typedef typename base_traits<derived_t>::value_type value_type;
value_type base_foo() {
return base_traits<derived_t>::call_foo(static_cast<derived_t*>(this));
}
};
// Define the derived class; it can use the traits too:
template <typename T>
struct derived : base<derived<T> > {
typedef typename base_traits<derived>::value_type value_type;
value_type derived_foo() {
return value_type();
}
};
// Declare and define a base_traits specialization for derived:
template <typename T>
struct base_traits<derived<T> > {
typedef T value_type;
static value_type call_foo(derived<T>* x) {
return x->derived_foo();
}
};
を特殊化するだけです。
base_traits
を特殊化する必要があります。
derived_t
の
base
のすべてのメンバを提供することを確認し、それぞれの特殊化が
base
が必要とするすべてのメンバーを提供するようにします。
関連
-
[解決済み】C-stringを使用すると警告が表示される。"ローカル変数に関連するスタックメモリのアドレスが返される"
-
[解決済み】抽象クラス型の無効なnew-expression
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】浮動小数点数の乱数生成
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み] C++11の'typedef'と'using'の違いは何ですか?
-
[解決済み] 派生クラス関数から親クラス関数を呼び出すには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】coutはstdのメンバではない
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】C-stringを使用すると警告が表示される。"ローカル変数に関連するスタックメモリのアドレスが返される"
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み】Eclipse IDEでC++エラー「nullptrはこのスコープで宣言されていません」が発生する件