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 的子类的一个部分定义它,除非它是一种明确的特化。

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

http://ideone.com/Vclac

编译没有错误。不需要中间体或类似的东西。

于 2011-06-11T11:47:51.803 回答
0

在构造函数中更改Base()Intermediary()Base<U>()Intermediary<Derived>使代码可以用于 GCC。

没有理由改变instances第二种情况的定义:模板与第一种情况相同。

于 2011-06-11T00:51:19.600 回答
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

以下使用 MinGW g++ 4.4.1、MSVC 10.0 和 Comeau Online 4.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 回答