1

多重継承を使用して、一種の CRTP (それが何であるかをよく理解している場合) を実装しようとしています。

私の主な目標は、各サブクラスのインスタンスのリストにアクセスするための統一された方法を持つことです。

名前空間の使用率に問題があるようです。

これが最も単純なバージョンのコードです: http://ideone.com/rFab5

私の本当の問題は、http: //ideone.com/U7cAfに似てい ます。

clang++ を使用して追加の警告があります:

test.cpp:28:63: warning: static data member specialization of 'instances' must originally be declared in namespace 'NS1'; accepted as a C++0x extension [-Wc++0x-extensions]
template <> std::list<NS1::Derived*> NS1::Base<NS1::Derived>::instances;
                                                          ^ 
test.cpp:15:34: note: explicitly specialized declaration is here
        static std::list<T*> instances;

名前空間を使用すると同じように動作しないため、問題が更新されました。

Ideone にコードを投稿するために再編集された問題

4

4 に答える 4

1

問題は、リスト変数を間違って定義しようとしたことです。一般に、Baseの定義を提供する必要があります。明示的な特殊化でない限り、Derivedのサブクラスである1つの部分に対して定義するだけではありません。

template<typename T> std::list<T*> NS1::Base<T>::instances;

http://ideone.com/Vclac

エラーなしでコンパイルします。中間体などは必要ありません。

于 2011-06-11T11:47:51.803 に答える
0

以下は、MinGW g ++ 4.4.1、MSVC 10.0、およびComeauOnline4.3.10.1で正常にコンパイルされます。

#include <list>

template <class T>
class Base
{
protected:
    Base()
    {
        instances.push_back(static_cast<T*>(this));
    }
private:
    static std::list<T*> instances;
};

template <class U>
class Intermediary : public Base<U>
{
protected:
    Intermediary()
    :Base<U>()
    {
    }
};

class Derived : public Intermediary<Derived>
{
public:
    Derived()
    :Intermediary<Derived>()
    {
    }
};

template<class Derived> std::list<Derived*> Base<Derived>::instances;

int main()
{}

定義はinstances質問から逐語的にコピーされます。

私はアイザックニュートンとして言います、私は仮説を立てません!

乾杯&hth。、

于 2011-06-11T04:04:34.463 に答える
0

Afaik、次のオプションがあります。
まず、Intermediateが常に派生型でテンプレート化されている場合、それが最も派生した型になることはないため、リストは必要ありません。他のタイプでテンプレート化できる/派生できない場合は、次のようにデフォルトの非タイプ bool テンプレート パラメーターを追加できます。

template<bool, class A, class B>
struct select_base{
  typedef A type;
};

template<class A, class B>
struct select_base<false,A,B>{
  typedef B type;
};

template<class T, bool IsDerived = false>
class Intermediate
  : public select_base<IsDerived,
                       Base<T>,
                       Base<Intermediate<T> >
                       >::type
{
  // ...
};

// derived use
class Derived : public Intermediate<Derived, true>
{
  // ...
};

// non-derived use:
Intermediate<int> im;

中間クラスがテンプレート化されておらず、まだ から派生していない場合は、最も派生したクラスで再度Base派生する必要があります。Base

class Derived : public Intermediate, public Base<Derived>
{
  // ...
};

大きな問題は、中間体も派生してBaseいるがテンプレート化されていない場合に発生します。デフォルトの派生型を追加できますが、非派生型の使用が少し見苦しくなります。

#include <type_traits> // C++0x, use std::
//#include <tr1/type_traits> // C++03, use std::tr1::

struct nil_base{};

template<class Derived = nil_base>
class Intermediate
  : public select_base<std::is_same<Derived,nil_base>::value,
                       Base<Intermediate<Derived> >, //
                       Base<Derived>
                       >::type
{
  // ...
};

// derived use now without boolean flag
class Derived : public Intermediate<Derived>
{
  // ...
};

// non-derived use a bit uglier
Intermediate<> im;
//          ^^ -- sadly needed
于 2011-06-11T01:38:43.560 に答える
0

Base()Intermediary()Base<U>()とに変更するとIntermediary<Derived>、コードは GCC でOKになります。

2 番目のケースでの定義を変更する理由はありませんinstances。テンプレートは最初の状況と同じです。

于 2011-06-11T00:51:19.600 に答える