CRTP子类和实例列表

发布于 2024-11-14 17:20:49 字数 873 浏览 5 评论 0原文

我正在尝试实现一种具有多重继承的 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 上发布代码

I'm trying to implement a kind of CRTP (if I well understand what it is) with multiple inheritance.

My main goal is to have a unified way to access list of instances of each subclass.

May problem seems to reside in the namespace utilization.

Here is the code of the simplest version :
http://ideone.com/rFab5

My real problem is more similar to :
http://ideone.com/U7cAf

I have an additional warning using 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;

Problem has been updated since it does not behave the same using namespaces.

Problem re-edited to post code on Ideone

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

等数载,海棠开 2024-11-21 17:20:49

问题是您尝试错误地定义列表变量。一般来说,您需要为 Base 提供一个定义 - 您不仅仅为恰好是 Derived 子类的一部分定义它,除非它是显式专业化。

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

http://ideone.com/Vclac

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

The problem is that you've tried to define the list variable wrong. You need to provide a definition for Base, in general- you don't just define it for the one part that happens to be Derived's subclass, unless it's an explicit specialization.

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

http://ideone.com/Vclac

Compiles with no errors. There are no intermediates or anything like that required.

坦然微笑 2024-11-21 17:20:49

Base()Intermediary() 更改为 Base()Intermediary构造函数使代码对于 GCC 来说OK

在第二种情况下没有理由更改实例的定义:模板与第一种情况相同。

Changing Base() and Intermediary() to Base<U>() and Intermediary<Derived> in the constructors makes the code OK for GCC.

There is no reason to change the definition of instances in the second case: the template is identical as the first situation.

追星践月 2024-11-21 17:20:49

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

Afaik, you got the following options.
First, if Intermediate is always templated on the derived type, you don't need a list for it, because it will never be the most derived type. If it could be templated on other types / not be derived, you can add a defaulted non-type bool template parameter like so:

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;

If the intermediate class is not templated and does not already derive from Base, you need to derive from Base again in the most derived class:

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

The big problem comes when the intermediate also derives from Base but is not templated. You can add a defaulted derived type, but that would make the non-derived use a bit more ugly:

#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
划一舟意中人 2024-11-21 17:20:49

以下内容可以在 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 定义是从您的问题中逐字复制的。

我说,作为艾萨克·牛顿,我不提出任何假设!

干杯&呵呵,

The following compiles OK with MinGW g++ 4.4.1, MSVC 10.0, and 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()
{}

The instances definition is copied verbatim from your question.

I say as Isaac Newton, I frame no hypotheses!

Cheers & hth.,

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文