c++派生类的类型列表

Posted

技术标签:

【中文标题】c++派生类的类型列表【英文标题】:c++ Typelist of derived class 【发布时间】:2012-05-29 06:28:43 【问题描述】:

使用 CRTP(奇怪的重复模板模式),您可以为基类提供从它派生的类的知识。创建一个数组来存储从基类派生的每个类的实例并不难(参见示例)

class Base
    public:
        static std::vector<Base *> m_derivedInstances;
;

template <class Derived>
class CRTPBase : public Base 
    public:
        static bool m_temp;
        static bool addInstance()
        
            m_derivedInstances.push_back(new Derived);
            return true;
        
;
template <class Derived>
CRTPBase<Derived>::m_temp = CRTPBase<Derived>::addInstance();

我想知道是否可以创建所有派生类类型的类型列表(请参阅http://www.research.ibm.com/designpatterns/pubs/ph-jun00.pdf)。问题是每次编译器看到一个派生自Base 的新类时,它都需要将新类型附加到列表中,但类型列表是不可变的(可以创建一个附加新类型的新列表,但据我所知,向列表中添加元素是不可能的。最后我想要这样的东西:

struct DerivedClassHolder 
    typedef Loki::TL::MakeTypeList</*list all derived classes here*/>::Result DerivedTypes;
;

最终目标是能够遍历所有派生自Base 的类。

【问题讨论】:

“遍历所有类”是什么意思 如果你一直在谈论“Base”,你可能走错了路。您没有基类。您有一个模板,每个新的派生类都可以从中获得自己的个人基类型。 另外,你想如何保证m_derivedInstances在你在全局范围内调用addInstance时已经被初始化了? 最后,我想遍历所有派生类型并对它们做一些事情(例如,使用 dynamic_cast 检查指向 Base 的指针到底是哪个派生类型。 m_derivedInstances 实际上并不是公共的,唯一可以访问它的是 addInstance ,它也是私有的,因此在初始化 m_temp 时唯一可以更改它的地方。我所要做的就是确保在 m_temp 之前初始化 m_derivedInstances。静态变量的初始化顺序只有在跨多个编译单元时才定义。 【参考方案1】:

可以使用伪类型映射来完成。下面是一些使用 boost::mpl 的示例代码。 “Implem”的显式定义可以通过每个对应的implem header中的宏来完成。

#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/push_front.hpp>
#include <boost/mpl/empty_sequence.hpp>
#include <boost/type_traits/is_same.hpp>

using namespace boost::mpl;
using namespace boost;


// A type map. Implem #N of type Key is type (default: void)

template <typename Key, int N>
struct Implem

  public:
    typedef void type;
;


// Type vector building functions
// void, the default type, is used to stop the recursion

template <typename Key, int N = 1>
struct ImplemToList;

template <typename Key, typename Item, int N>
struct ImplemListItem

  public:
    typedef typename push_front<typename ImplemToList<Key, N + 1>::type, Item>::type type;
;

template <typename Key, int N>
struct ImplemToList

  public:
    typedef typename Implem<Key, N>::type item;
    typedef typename eval_if<is_same<item, void>,
                             identity<vector<> >,
                             ImplemListItem<Key, item, N> >::type type;
;


// Example code: an interface with two implems

class Interface

  public:
    virtual const char* name() const = 0;
;

class Implem1 : public Interface

  public:
    virtual const char* name() const  return "implem_1"; 
;

class Implem2 : public Interface

  public:
    virtual const char* name() const  return "implem_2"; 
;

template <>
struct Implem<Interface, 1>

  public:
    typedef Implem1 type;
;

template <>
struct Implem<Interface, 2>

  public:
    typedef Implem2 type;
;


void print(Interface const& i)

  std::cout << i.name() << std::endl;


int main()

  typedef ImplemToList<Interface>::type IList;
  for_each<IList>(&print);

【讨论】:

【参考方案2】:

您的类型列表只能手动创建。你提到的问题,不变性,是无法克服的。

【讨论】:

假设我想手动创建 Typelist,但我希望能够更新列表而无需更改 Base 或 DerivedClassHolder 的定义。有点为列表创建别名,但实际列表可以从外部更改。 @BenjyKessler - 您无法更改列表。时期。当然,您始终可以手动编译一个新列表并使用该列表,但您不能替换任何现有列表,因此您只需要知道众多列表中的哪一个包含它应该包含的所有值。 好的,谢谢,我会试着想一些其他的做事方式。

以上是关于c++派生类的类型列表的主要内容,如果未能解决你的问题,请参考以下文章

C++学习之路派生类的构造函数

无法将派生类 push_back() 推入 C++ 中的 STL 列表

C++ 静态多态性 (CRTP) 和使用派生类的 typedef

C++ 类型将基础对象转换为派生对象

C++ 继承&多态

C++学习之路派生类的构造函数