c++11模拟boost元占位符(一)

2015-01-27 14:02:54 · 作者: · 浏览: 55
准备实现meta programming的fold函数,发现自己缺少占位符实现,这样传入fold的transform op类(元函数)都不得不另外写个外覆类,其实我觉得没啥不好,简单直接,说实话干扰什么的没那么严重,一个功能块里能用fold的地方能有几次?但动了占位符这个念头,就想尝试实现一下。
?
看一下实际情景:
?
template
struct fold_s ?{};
我们可能会希望把push_back作为运算子传入fold_s中,从而实现循环迭代TList的每一个元素,对其应用push_back。如:
?
using type = fold_s, nullist, push_back>::type;
问题是,push_back并不是一个类,只是一个声明,push_back如此才是一个真正的类,而一般只有类才能作为实参传入。
?
最直接的做法是写个外覆类:
?
复制代码
? ? struct push_back_wrap
? ? {
? ? ? ? template
? ? ? ? struct apply
? ? ? ? {
? ? ? ? ? ? using type = typename mpl::push_back::type;
? ? ? ? };
? ? };
复制代码
传入fold_s然后调用apply:
?
复制代码
? ? template
? ? struct fold_s
? ? {
? ? ? ? using sometype = typename TransformOp::apply::type;
? ? };
? ??
? ? using type = fold_s, nullist, push_back>::type;
复制代码
我们知道很多函数语言的一个特征就是延迟计算。此处push_back_wrap中的嵌套类apply,使得push_back_wrap也具有延迟的特性,类型计算直到fold_s真正应用apply时
?
才发生。这就是meta programming中实现lambada的手法。缺点是我们必须要在使用lambda元类的地方都默认假设apply存在。相比于它的强大功能,因为c++ mpl的
?
限制导致这个小不便,我们就忍忍吧。
?
以上说明了一个占位符将要应用的情境。下面就开始no zuo no die的处理吧。其实就是有些人不希望每次用flod_s时都要写个外覆类,他们希望当flod_s需要传入push_back
?
时就直接传入push_back,好看好记些。很明显那只能传入一个push_back的特化了。
?
fold< vector, vector<>, push_back<_1, _2> >::type;
上边的_1,_2就是占位符了。push_back<_1, _2>就是我们所讨论的特化的。显然_1, _2是个类,在上述语句中分别指vector<>,int,总之占位符将指定你需要指定的位置。
?
这个特化既然取代了外覆类,那它必然提供了相似的功能。也就是push_back必然是个类型延迟的元函数类,它具有类似下面的结构:
?
复制代码
? ? struct push_back<...>
? ? {
? ? ? ? struct apply
? ? ? ? {
? ? ? ? ? ? type...
? ? ? ? };
? ? };
复制代码
那么在fold_s内当调用push_back::apply时,显然push_back必须要具备从参数列表中挑选指定参数的能力,自然的,这个任务就交给_1,_2占位符了。实现的办法你可以
?
去查看boost mpl库的做法,也可使用我下边的做法(需要c++11支持):
?
复制代码
#ifndef HI_MPL_PLACEHOLDERS_H_INCLUDED
#define HI_MPL_PLACEHOLDERS_H_INCLUDED
?
//////////////////////////////////////////////////////////////////////
namespace hi { namespace mpl {
? ??
? ? //surport palceholders is too painful?
? ? namespace placeholders
? ? {
? ? ? ? namespace helper?
? ? ? ? {
? ? ? ? ? ? template struct arglist { };
? ? ? ? ? ? typedef arglist<> nullargs;
?
? ? ? ? ? ? template struct at;
?
? ? ? ? ? ? template
? ? ? ? ? ? struct at< N, arglist >
? ? ? ? ? ? {
? ? ? ? ? ? ? ? typedef typename at< N - 1, arglist >::type type;
? ? ? ? ? ? };
?
? ? ? ? ? ? template
? ? ? ? ? ? struct at< 0, arglist >
? ? ? ? ? ? {
? ? ? ? ? ? ? ? typedef T type;
? ? ? ? ? ? };
?
? ? ? ? } // end of placeholders::helper
?
? ? ? ? template struct Arg
? ? ? ? {
? ? ? ? ? ? template
? ? ? ? ? ? struct apply
? ? ? ? ? ? {
? ? ? ? ? ? ? ? using type = typename helper::at >::type;
? ? ? ? ? ? };
?
? ? ? ? private:
?
? ? ? ? };
?
? ? ? ? using _1 = Arg<1>;
? ? ? ? using _2 = Arg<2>;
? ? ? ? using _3 = Arg<3>;
? ? ? ? using _4 = Arg<4>;
? ? } // end of placeholders
?
}
}
#endif
复制代码
如上,_1::apply::type为int, ?_2::apply::type为char。若不太清楚原理请参考:
http://www.cnblogs.com/flytrace/p/3551414. html
?
以上要注意的arglist是从0开始索引的,而外部Arg是从1开始索引的。
?
至此让我们把push_back<_1, _2>完成:
?
复制代码
? ? template<> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? struct push_back< _1, _2 > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? template ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? struct apply ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? using type = typename push_back< ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?typename _1::apply::type, ? ? ? ? ? ? ? ? ? ? ?