7

単純な形式の CRTP (Curiously Recurring Template Pattern) を使用しようとしています。いくつかのクラスがあり、それぞれにいくつかの関連クラスがあり、それらを結合する手段が必要です (たとえば、Widget のようなクラスがあります)。関連するクラス WidgetHandle、DoobryHandle、および WhatsitHandle を持つ Doobry および Whatsit)。

継承元として使用している各クラスはtypedefをBase追加して、基本クラスがそれを として参照できるようにします。value_typetypename 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 の場合ですが、clang で同様のエラーが発生します。ここで何が欠けていますか?

4

2 に答える 2

1

Base の定義を変更して、ハンドル型を 2 番目のパラメーターとして使用し、循環依存を回避します。

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;
}

特性クラスを使用して Widget の 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;
}
于 2013-08-22T13:54:06.650 に答える
1

循環的な依存関係を持つことはできません。ベースは、ベースのインスタンス化では不明な Widget value_type を必要とします。

考えられる解決策は次のとおりです: value_type を Base テンプレート パラメーターとして渡す、追加の Traits テンプレートを使用する、...

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>
{
};
于 2013-08-22T13:48:37.360 に答える