sur*_*ode 2 c++ metaprogramming template-meta-programming
我想要做的确切此获得类型/类的列表.但我不能使用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;
}
Run Code Online (Sandbox Code Playgroud)
首先,您的代码无法编译的实际问题是您要键入操作,而不是结果.像这样改变它:
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;
Run Code Online (Sandbox Code Playgroud)
现在更全面地了解为什么需要typedef.
使用元编程技术(如你的情况下的模板元编程)需要精神上的"转变",因为范式不同于"普通"C++.C++本身就是一种命令式语言.Metaprograms是功能性的.
就数据结构而言,功能范例意味着数据结构总是不可变的.例如,在命令式语言中,您执行此操作:
vector<int> v;
v.push(4);
v.push(7);
v.push(42);
process(&v);
print(v);
Run Code Online (Sandbox Code Playgroud)
在函数式语言中,等效代码为:
v = vector<int>;
v1 = v.push(4);
v2 = v1.push(7);
v3 = v2.push(42);
v4 = process(v3);
print(v4);
Run Code Online (Sandbox Code Playgroud)
或者,使用更多功能表示法,如下所示:
print(process(vector<int>().push(4).push(7).push(42)));
Run Code Online (Sandbox Code Playgroud)
在纯功能(LISP风格)表示法中,它将是:
(print (process (push (push (push (vector<int>) 4) 7) 42)))
Run Code Online (Sandbox Code Playgroud)
另一种方法是在函数式语言中,不存储数据结构,而是生成数据结构.
反观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
直接调用宏,而是#include
d,类名通过另一个宏传递.像这样的东西:
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)
Run Code Online (Sandbox Code Playgroud)
registration.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))
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
当涉及多个翻译单元时,需要进行一些调整才能正常工作(在这种情况下根本无法完成某些事情,如果将适当的标识符放在匿名名称空间中,则可以完成某些操作).但它应该作为一个起点.