c++11模拟boost元占位符placeholder
准备实现meta programming的fold函数,发现自己缺少占位符实现,这样传入fold的transform op类(元函数)都不得不另外写个外覆类,其实我觉得没啥不好,简单直接,说实话干扰什么的没那么严重,一个功能块里能用fold的地方能有几次?但动了占位符这个念头,就想尝试实现一下。
看一下实际情景:
template<typename TList, typename Init, class TransformOp>
struct fold_s {};
我们可能会希望把push_back作为运算子传入fold_s中,从而实现循环迭代TList的每一个元素,对其应用push_back。如:
using type = fold_s<typelist<int, float, char>, nullist, push_back>::type;
问题是,push_back并不是一个类,只是一个声明,push_back<somelist, t>如此才是一个真正的类,而一般只有类才能作为实参传入。
最直接的做法是写个外覆类:
struct push_back_wrap
{
template<typename TList, typename T>
struct apply
{
using type = typename mpl::push_back<TList, T>::type;
};
};
传入fold_s然后调用apply:
template<typename TList, typename Init, class TransformOp>
struct fold_s
{
using sometype = typename TransformOp::apply<TList, T>::type;
};
using type = fold_s<typelist<int, float, char>, nullist, push_back_wrap>::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<int, float, char>, 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<typename... TList> struct arglist { };
typedef arglist<> nullargs; template<unsigned int N, typename... TList> struct at; template<unsigned int N, typename T, typename... TList>
struct at< N, arglist<T, TList...> >
{
typedef typename at< N - 1, arglist<TList...> >::type type;
}; template<typename T, typename... TList>
struct at< 0, arglist<T, TList...> >
{
typedef T type;
}; } // end of placeholders::helper template<int n> struct Arg
{
template<typename ... TList>
struct apply
{
using type = typename helper::at<n - 1, helper::arglist<TList...> >::type;
}; private: }; using _1 = Arg<1>;
using _2 = Arg<2>;
using _3 = Arg<3>;
using _4 = Arg<4>;
} // end of placeholders }
}
#endif
如上,_1::apply<int, char, float>::type为int, _2::apply<int, char, float>::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<typename... TList>
struct apply
{
using type = typename push_back<
typename _1::apply<TList...>::type,
typename _2::apply<TList...>::type>::type;
};
};
fold_s把固定的一堆参数传入时,push_back总能挑选到正确位置的参数。下面我们来看看一个奇妙的改变,这将会让你恍然大悟_1, _2占位符的设计和来历。
让我们把上面的代码中所有_1,_2的地方全部调换位置,得到一个新的特化:
template<>
struct push_back< _2, _1 >
{
template<typename... TList>
struct apply
{
using type = typename push_back<
typename _2::apply<TList...>::type,
typename _1::apply<TList...>::type>::type;
};
};
使用这个新特化时,fold_s传入的第二个参数将被放到push_back的第一个参数位置,而_2位于push_back第一个参数的样子正好很形象的描述了这个行为。
现在你明白了吧,push_back<_1,_2>和push_back<_2,_1>这2个特化组合在一起,让我们有了能够指称第一,第二个参数的能力。
这确实非常帅。很可惜当参数个数n增长时,你需要覆盖n!种特化。参数为5时你将不得不写120个特化。boost使用preprocessor来自动生成这些类,你仔细观察上述类的结构,
确实都是可以自动生成的。我表示看了preprocessor几眼就要瞎掉,有兴致再研究。下面是我写的更简单的自动构造宏:
#ifndef HI_MPL_SUPPORT_LAMBDA_H_INCLUDE
#define HI_MPL_SUPPORT_LAMBDA_H_INCLUDE #define SUPPORT_LAMBDA_1_IMPL(classname, A1) \
template<> \
struct classname##< A1 > \
{ \
template<typename... TList> \
struct apply \
{ \
using type = typename classname##< \
typename A1::apply<TList...>::type>::type; \
}; \
}; #define SUPPORT_LAMBDA_2_IMPL(classname, A1, A2) \
template<> \
struct classname##< A1, A2 > \
{ \
template<typename... TList> \
struct apply \
{ \
using type = typename classname##< \
typename A1::apply<TList...>::type, \
typename A2::apply<TList...>::type>::type; \
}; \
}; #define SUPPORT_LAMBDA_3_IMPL(classname, A1, A2, A3) \
template<> \
struct classname##< A1, A2, A3 > \
{ \
template<typename... TList> \
struct apply \
{ \
using type = typename classname##< \
typename A1::apply<TList...>::type, \
typename A2::apply<TList...>::type, \
typename A3::apply<TList...>::type>::type; \
}; \
}; #define SUPPORT_LAMBDA_4_IMPL(classname, A1, A2, A3, A4) \
template<> \
struct classname##< A1, A2, A3, A4 > \
{ \
template<typename... TList> \
struct apply \
{ \
using type = typename classname##< \
typename A1::apply<TList...>::type, \
typename A2::apply<TList...>::type, \
typename A3::apply<TList...>::type \
typename A4::apply<TList...>::type>::type; \
}; \
}; #define SUPPORT_LAMBDA_5_IMPL(classname, A1, A2, A3, A4, A5) \
template<> \
struct classname##< A1, A2, A3, A4, A5 > \
{ \
template<typename... TList> \
struct apply \
{ \
using type = typename classname##< \
typename A1::apply<TList...>::type, \
typename A2::apply<TList...>::type, \
typename A3::apply<TList...>::type \
typename A4::apply<TList...>::type \
typename A5::apply<TList...>::type>::type; \
}; \
}; #define SUPPORT_LAMBDA_1(classname, P) \
SUPPORT_LAMBDA_1_IMPL(classname, P##) #define SUPPORT_LAMBDA_2(classname, P) \
SUPPORT_LAMBDA_2_IMPL(classname, P##, P##) \
SUPPORT_LAMBDA_2_IMPL(classname, P##, P##) #define SUPPORT_LAMBDA_3(classname, P) \
SUPPORT_LAMBDA_3_IMPL(classname, P##, P##, P##) \
SUPPORT_LAMBDA_3_IMPL(classname, P##, P##, P##) \
SUPPORT_LAMBDA_3_IMPL(classname, P##, P##, P##) \
SUPPORT_LAMBDA_3_IMPL(classname, P##, P##, P##) \
SUPPORT_LAMBDA_3_IMPL(classname, P##, P##, P##) \
SUPPORT_LAMBDA_3_IMPL(classname, P##, P##, P##) #define SUPPORT_LAMBDA_4(classname, P) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) \
SUPPORT_LAMBDA_4_IMPL(classname, P##, P##, P##, P##) #define SUPPORT_LAMBDA(classname, n, prefix) \
SUPPORT_LAMBDA_##n(classname, prefix) #endif
在每个你希望支持占位符的类定义后边,加上SUPPORT_LAMBDA这句宏,填入参数总数,占位符前缀(可包含命名空间,默认占位符必须以本身数字结束)。如下例子
template<typename T, typename... TList> struct push_back; template<typename T, typename... TList>
struct push_back< typelist<TList...>, T>
{
typedef typelist<TList..., T> type;
}; template<>
struct push_back< nulllist >
{
typedef nulllist type;
}; SUPPORT_LAMBDA(push_back, , placeholders::_);
以上这一套实现占位符的办法,比boost的要简洁了很多。当然还缺少匿名占位符这样的手法,这里提供一个简易的思路,望你有所得。
c++11模拟boost元占位符placeholder的更多相关文章
- 输入框占位符placeholder
占位符placeholder的益处不用多说,但是很不幸的是,在IE8之前的浏览器里是无法实现placeholder这一属性的,所以在需要兼容IE8之前的浏览器的情况下,我们不得不想办法模拟实现plac ...
- [Sass]占位符 %placeholder
[Sass]占位符 %placeholder Sass 中的占位符 %placeholder 功能是一个很强大,很实用的一个功能,这也是我非常喜欢的功能.他可以取代以前 CSS 中的基类造成的代码冗余 ...
- 占位符(placeholder text)
占位符(placeholder text)是用户在input(输入)框输入任何东西之前放置在input(输入)框中的预定义文本. 你可以用如下方式创建占位符: <input type=" ...
- IE8支持HTML5的占位符placeholder
/*IE8支持placeholder占位符*/ if( !('placeholder' in document.createElement('input')) ){ $('input[placehol ...
- tensorflow中常量(constant)、变量(Variable)、占位符(placeholder)和张量类型转换reshape()
常量 constant tf.constant()函数定义: def constant(value, dtype=None, shape=None, name="Const", v ...
- sass 继承 占位符 %placeholder
@extend //SCSS .btn { border: 1px solid #ccc; padding: 6px 10px; font-size: 14px; } .btn-primary { b ...
- RunTime运行时在iOS中的应用之UITextField占位符placeholder
RunTime运行时机制 runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API. 在我们平时编写的Objective-C代码中, 程序运行过程时, 其实最终 ...
- based on Greenlets (via Eventlet and Gevent) fork 孙子worker 比较 gevent不是异步 协程原理 占位符 placeholder (Future, Promise, Deferred) 循环引擎 greenlet 没有显式调度的微线程,换言之 协程
gevent GitHub - gevent/gevent: Coroutine-based concurrency library for Python https://github.com/gev ...
- sass---Sass混合宏、继承、占位符
混合宏-声明混合宏如果你的整个网站中有几处小样式类似,比如颜色,字体等,在 Sass 可以使用变量来统一处理,那么这种选择还是不错的.但当你的样式变得越来越复杂,需要重复使用大段的样式时,使用变量就无 ...
随机推荐
- 随机森林RF、XGBoost、GBDT和LightGBM的原理和区别
目录 1.基本知识点介绍 2.各个算法原理 2.1 随机森林 -- RandomForest 2.2 XGBoost算法 2.3 GBDT算法(Gradient Boosting Decision T ...
- MVC实战之排球计分软件(深入了解面向对象编程)
在此篇博客之前,我已经写了一个实战系列的博客,虽然不太成熟但是相对比较实用,在这篇博客我将继续使用mvc编程此软件. 此篇博客会在一定的时间内完成,此次完成的软件的一个需求是提供给运动员的使用.我将在 ...
- jQuery中$(function(){})与(function($){})(jQuery)、$(document).ready(function(){})等的区别详解
1.(function($) {…})(jQuery); 1).原理: 这实际上是匿名函数,如下: function(arg){…} 这就定义了一个匿名函数,参数为arg 而调用函数时,是在函数后面写 ...
- [sgu P155] Cartesian Tree
155. Cartesian Tree time limit per test: 0.25 sec. memory limit per test: 65536 KB input: standard i ...
- html5(八) IndexedDB
IndexedDB 是一个数据库系统,它在用户的计算机上存储索引信息. IndexedDB与传统的数据库不同.在IndexedDB中,数据库中的信息以对象的形式存储在对象库表中.对象库没有特定的结构, ...
- JAVA 创建文件和文件夹,删除文件和文件夹的实用工具
package com.file; import java.io.File; import java.io.IOException; //创建新文件和目录 public class CCRDFile ...
- 1. qt 入门-整体框架
总结: 本文先通过一个例子介绍了Qt项目的大致组成,即其一个简单的项目框架,如何定义窗口类,绑定信号和槽,然后初始化窗口界面,显示窗口界面,以及将程序的控制权交给Qt库. 然后主要对Qt中的信号与槽机 ...
- 阶段01Java基础day23多线程
23.01_多线程(多线程的引入) 1.什么是线程 线程是程序执行的一条路径, 一个进程中可以包含多条线程 多线程并发执行可以提高程序的效率, 可以同时完成多项工作 2.多线程的应用场景 红蜘蛛同时共 ...
- java中求余%与取模floorMod的区别
初学java的时候接触的%这个符号 百分号? 求余? 取模? 我只知道不是百分号,好像是求余,听别人那叫求模运算符,跟求余一样,于是我便信了. 思考之后开始迷糊,然后经过多次考证得到以下结论. 首先, ...
- C基础学习笔记
1.C语言运算符优先级: 2.三种循环比较 while.do-while和for三种循环在具体的使用场合上是有区别的,如下: 1).在知道循环次数的情况下更适合使用for循环: 2).在不知道循环次数 ...