2013-08-22 12 views
6

複数のクラスがあり、バインディング手段が必要なので、シンプルな形式のCRTP(Curiously Recurring Template Pattern)を使用しようとしています。一緒に(例えば私はWidget、Doobry、WhatsitのようなクラスをWidgetHandle、DoobryHandle、WhatsitHandleといった関連クラスと一緒に持っています)。依存型を持つ単純なCRTPの場合のコンパイルエラー

私がBaseから継承するために使用している各クラスは typedefを追加しており、基本クラスでtypename TWrapper::value_typeと参照できるようになっています。

struct WidgetHandle {}; 

template <typename TWrapper> 
class Base 
{ 
public: 
    Base(typename TWrapper::value_type value_) 
     : value(value_) {} 

    typename TWrapper::value_type value; 
}; 

class Widget : public Base<Widget> 
{ 
public: 
    typedef WidgetHandle value_type; 

    Widget(WidgetHandle value_) : Base<Widget>(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 

しかし、私はコンパイルエラーを取得しています:

scratch1.cpp(10): error C2039: 'value_type' : is not a member of 'Widget' 
scratch1.cpp(16) : see declaration of 'Widget' 
scratch1.cpp : see reference to class template instantiation 'Base<TWrapper>' being compiled 
1>   with 
1>   [ 
1>    TWrapper=Widget 
1>   ] 
scratch1.cpp(10): error C2039: 'value_type' : is not a member of 'Widget' 

私が打ち鳴らすと同様のエラーを取得していますが、これは、VS2010です。私はここで何が欠けていますか?

+0

'Widget'は' Base'へのパラメータとして渡すと完全ではありません。 – jrok

+0

実際には、どこにでもvalue_typeが定義されていません。 – lapk

+0

@PetrBudnikウィジェット本体の先頭です。 – jrok

答えて

1

循環依存性を回避するための第2パラメータとしてndle型を使用します。

struct WidgetHandle {}; 

template <typename TWrapper, typename HandleType> 
class Base 
{ 
public: 
    typedef HandleType value_type; 

    Base(HandleType value_) 
     : value(value_) {} 

    HandleType value; 
}; 

class Widget : public Base<Widget, WidgetHandle> 
{ 
public: 
    Widget(WidgetHandle value_) : Base(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 

また、ウィジェットのためWidgeHandleタイプを取得する特性クラスを使用することができます。

struct WidgetHandle {}; 
class Widget; 

template<class T> 
struct Handle 
{ 
}; 

template<> 
struct Handle<Widget> 
{ 
    typedef WidgetHandle type; 
}; 

template <typename TWrapper, typename HandleType = Handle<TWrapper>::type> 
class Base 
{ 
public: 
    typedef HandleType value_type; 

    Base(HandleType value_) 
     : value(value_) {} 

    HandleType value; 
}; 

class Widget : public Base<Widget> 
{ 
public: 
    Widget(WidgetHandle value_) : Base(value_) {} 
}; 

int main(int argc, char* argv[]) 
{ 

    Widget i(WidgetHandle()); 
    return 0; 
} 
+0

テンプレート定義に余分な型を追加することができますが、TWrapperにバインドされている型を指定する手段がある場合は残念です –

+0

デフォルトテンプレートパラメータを使用して、traitsクラスからハンドル型を取得します。クライアントのコードは同じように見えます。 – paxos1977

+0

それはトリックです。私の場合、クラスごとにいくつかの関連する型があるので、それらをHandleのtraitsクラスと結びつけると、それらをすべて1つで宣言することができます。 –

1

循環依存関係を持つことはできません。ベースには、Baseインスタンシエーションで不明なウィジェットのvalue_typeが必要です。

可能な解決策は、次のようになります。

...、余分な形質のテンプレートを使用し、基本テンプレートパラメータとしてVALUE_TYPEを渡します

template <typename W> 
struct WidgetTraits {}; 

template <typename W> 
class Base 
{ 
    public: 
    typedef typename WidgetTraits<W>::value_type value_type; 
}; 

class Widget; 

template<> 
struct WidgetTraits<Widget> 
{ 
    typedef WidgetHandle value_type; 
}; 

class Widget : public Base<Widget> 
{ 
}; 

別(若干異なる)の例

template <typename C, typename A> 
class B : public A 
{ 
    public: 
    typedef typename A::value_type value_type; 
}; 


class A 
{ 
    public: 
    typedef WidgetHandle value_type; 
}; 


class C : public B<C, A> 
{ 
}; 
+0

これは一般に当てはまりますが、CRTPはこの技術を広く使用していますか? http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern –

+0

大丈夫ですが、特性テンプレートはより良いかもしれません - そのように見えますか? –

+0

形質の解はもっと複雑です...私は追加のテンプレートパラメータを求めます。 – Walter

関連する問題