首先,代码无法编译的实际问题是您正在对操作进行类型定义,而不是对它们的结果进行类型定义。像这样改变它:
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)))
另一种说法是,在函数式语言中,数据结构不是stored,他们是产生的。
回到 C++ 模板元编程和 Boost.MPL,这意味着附加类型的唯一方法T
到类型列表(MPL 向量)v
是要通过boost::mpl::push_back<v, T>::type
在那里你想要处理“向量”T
推回“。以维持DRY http://en.wikipedia.org/wiki/Don%27t_repeat_yourself,您通常使用“向量”的 typedef 来执行此操作T
推后。”
不幸的是,这意味着没有办法创建一个REGISTER_CLASS
按照您想要的方式进行宏操作。您可以通过更多元编程(包括使用 Boost.Preprocessor)来制作类似的东西。
这个想法是使用 Boost.Preprocessorslot保存类型列表的最后一个标识符。而不是调用REGISTER_CLASS
直接宏,那就是#include
d,类名通过另一个宏传递。像这样的事情:
内部寄存器.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;
}
当涉及多个翻译单元时,需要进行更多调整才能正常工作(在这种情况下,有些事情根本无法完成,如果将适当的标识符放入匿名命名空间中,则可以完成有些事情)。但它应该作为一个起点。