2

我想这样做获得类型/类的列表。但我不能使用 C++11。有什么建议可以将类型附加到模板列表吗?

编辑:我想做的一些代码:

#include <iostream>
#include <typeinfo>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/for_each.hpp>

using namespace std;

class A {};
class B {};
class C {};

typedef boost::mpl::vector<> type1;
// supposed I'd like to have this as a #define macro so someone can call
// REGISTER_CLASS(A) and push the type into a list
typedef boost::mpl::push_back<type1, A> type2;
typedef boost::mpl::push_back<type2, B> type3;
typedef boost::mpl::push_back<type3, C> type4;

template <typename T> struct wrap {};

struct Print
{
      template <typename T> void operator()( wrap<T> t ) const
      {
            cout << typeid( T ).name() << endl;
      }
};

int main()
{
      // this doesn't compile because type4 is a sequence of sequence
      // supposed, I need to "flatten" this list so it's eqv to vector<A,B,C>
      boost::mpl::for_each<type4, wrap<boost::mpl::placeholders::_1> >( Print() );

      // second problem is that I'd like to have typedef of 1 typelist only, not
      // type1, type2, ... typeN, since I don't know the exact number of classes

      return 0;
}
4

1 回答 1

5

首先,您的代码无法编译的实际问题是您正在对操作进行类型定义,而不是它们的结果。像这样改变它:

typedef boost::mpl::push_back<type1, A>::type type2;
typedef boost::mpl::push_back<type2, B>::type type3;
typedef boost::mpl::push_back<type3, C>::type type4;

现在更一般地了解为什么需要 typedef。

使用元编程技术(如您的情况下的模板元编程)需要心理“转变”,因为范式不同于“普通”C++。C++ 本身是一种命令式语言。元程序是功能性的。

就数据结构而言,功能范式意味着数据结构始终是不可变的。例如,在命令式语言中,您可以这样做:

vector<int> v;
v.push(4);
v.push(7);
v.push(42);
process(&v);
print(v);

在函数式语言中,等效代码为:

v = vector<int>;
v1 = v.push(4);
v2 = v1.push(7);
v3 = v2.push(42);
v4 = process(v3);
print(v4);

或者,使用更多功能符号,如下所示:

print(process(vector<int>().push(4).push(7).push(42)));

在纯函数式(LISP 风格)表示法中,它将是:

(print (process (push (push (push (vector<int>) 4) 7) 42)))

另一种说法是,在函数式语言中,数据结构不是存储的,而是生成的。

回到 C++ 模板元编程和 Boost.MPL,这意味着将类型附加T到类型列表(MPL 向量)的唯一方法v是将那里传递boost::mpl::push_back<v, T>::type到您要处理“T推回向量”的位置。为了保持DRY,您通常使用 typedef 为“带T推回的向量”执行此操作。


不幸的是,这意味着无法按照REGISTER_CLASS您想要的方式创建宏。您可以通过更多元编程(包括使用 Boost.Preprocessor)来制作类似的东西。

这个想法是使用 Boost.Preprocessor来保存类型列表的最后一个标识符。不是REGISTER_CLASS直接调用宏,而是#included,类名通过另一个宏传递。像这样的东西:

internal_register.hpp

//This file MUST NOT have include guards

#ifndef CLASS_TO_REGISTER
  #error You must define CLASS_TO_REGISTER before executing REGISTER_CLASS()
#endif

typedef boost::mpl::push_back<
  CURRENT_TYPELIST(),
  CLASS_TO_REGISTER
>::type BOOST_PP_CAT(registered, BOOST_PP_INC(BOOST_PP_SLOT(1)));

#undef CLASS_TO_REGISTER

#define BOOST_PP_VALUE BOOST_PP_SLOT(1) + 1
#include BOOST_PP_ASSIGN_SLOT(1)

注册.hpp

typedef boost::mpl::vector<>::type registered0;

#define BOOST_PP_VALUE 0
#include BOOST_PP_ASSIGN_SLOT(1)

#define REGISTER_CLASS() "internal_register.hpp"

#define CURRENT_TYPELIST() BOOST_PP_CAT(registered, BOOST_PP_SLOT(1))

main.cpp(或任何其他用法):

#include "registration.hpp"

class A {};
class B {};
class C {};

#define CLASS_TO_REGISTER A
#include REGISTER_CLASS()

#define CLASS_TO_REGISTER B
#include REGISTER_CLASS()

#define CLASS_TO_REGISTER C
#include REGISTER_CLASS()

template <typename T> struct wrap {};

struct Print
{
      template <typename T> void operator()( wrap<T> t ) const
      {
            cout << typeid( T ).name() << endl;
      }
};

int main()
{
      boost::mpl::for_each<CURRENT_TYPELIST(), wrap<boost::mpl::placeholders::_1> >( Print() );

      return 0;
}

当涉及多个翻译单元时,需要进行更多调整才能正常工作(在这种情况下,有些事情根本无法完成,如果将适当的标识符放在匿名命名空间中,有些事情可以完成)。但它应该作为一个起点。

于 2013-10-28T09:12:22.513 回答