C++11实现placeholder

文章分析怎样在C++11中实现简单的placeholder。ios


首先看看什么是placeholder:
for_each(arr.begin(), arr.end(), cerr << _0 << endl);
当中arr的类型是vector<int>,第三个參数是一个表达式,表达式中有一个操做数是_0。第三个參数含义是对这个表达式进行求值,获得一个对象x,x拥有operator ()(int a)的成员函数。整个表达式意味着把arr的每一个元素b取出来。而后调用x(b)。而x(b)的效果是将b输出到一行当中。当中的_0就是placeholder,在表达式中做为一个占位符存在,等待外部给出_0的类型和值的时候,整个表达式再求值。

这是个很是酷的语法糖。在C++11中可以用lambda表达式取代,只是弄明确怎么实现对于模板元编程的能力会有所提高。如下来分析一下怎样去实现placeholder:

考虑_0, _1这些占位符,首先搞明确它们在C++中的语法成份。出现在表达式中,而且表达式不是处于某个模板的环境。可以确定在编译时能知道表达式的所有操做数的类型。

_0可以是一个形如被定义为make_placeholder0()的宏。也可以是T0 _0;之类的一个对象。只是这没有关系,咱们仅仅关心_0这个表达式的类型。可以看出_0应该具备类类型。operator << 能做用于该类型的对象上。c++

占位符和其余操做数进行运算,会产生新的类型,新的类型还可以參加运算,最后使得cerr << _0 << endl这个表达式具备某个类型。咱们假定这个产生的新的类型是TExpr。TExpr在运算后仍然是TExpr类型。假设把语法树的结点用类型标注一下,对于表达式_0 + _1 - _2应该是例如如下结果编程


                       - : TExpr
               + : TExpr      _2 : T2

         _0 : T0  _1 : T1架构


TExpr将拥有operator ()。能够求值。但是眼下看来TExpr上的operator () 具备不肯定性:
根结点上,operator将使用两个操做数。把减法操做应用在两个操做数上。
在左边的结点上,是将加法应用在两个操做数上。



因此TExpr中的operator ()是多态的。函数

假设将语法树改成:
                       - : TExpr<MinusTag>
               + : TExpr<AddTag>      _2 : T2
         _0 : T0  _1 : T1
事情就变得easy一些,TExpr是參数化的,依据不一样的Tag參数,在operator ()时有不一样的行为。

可以预见咱们应该构造一堆这种类:
post

template<typename L, typename R, typename T>
class TExpr;


template<typename L, typename R>
class TExpr<L, R, AddTag>
{
	L left_operand;
	R right_operand;
};


template<typename L, typename R>
class TExpr<L, R, SubTag>
{
	L left_operand;
	R right_operand;
};
当中L,R两个类型多是T0。T1等占位符的类型,或者是TExpr<,,,>,或者是其余类型。但是这样作有个缺点。把參数个数写死了。因而将上面的AddTag和TExpr组合到一块儿,造成
template<typename T1, typename T2>
struct TExprAdd
{
};
template<typename T1, typename T2>
struct TExprSub
{
};
进一步,将_0和_1的类型定义为:
template<int v>
struct TExprBasic
{
};
并提供操做:
template<typename T1, typename T2>
TExprAdd<T1, T2> 
operator + (T1 a, T2 b)
{
	typedef TExprAdd<T1, T2> TI;
	return TI(a, b);
}


template<typename T1, typename T2>
TExprSub<T1, T2> 
operator - (T1 a, T2 b)
{
	typedef TExprSub<T1, T2> TI;
	return TI(a, b);
}
因而语法树变为:


                        - : TExprSub<TExprAdd<TExprBasic<0>, TExprBasic<1>>, TExprBasic<2>>
                + : TExprAdd<TExprBasic<0>, TExprBasic<1>>          _2 : TExprBasic<2>
     _0 : TExprBasic<0>  _1 : TExprBasic<1>

至此,咱们已经给出了一个可以用的placeholder的架构了。

咱们要求TExprAdd,TExprSub拥有一些共性,知足某个concept,这个concept就是TExpr。这个concept是本身在编程中心中默默创建的。固然也可以把这个concept用显式的方式写出来:
<pre name="code" class="cpp">template<typename T>
class TExpr
{
	// require 1:T具备计算返回类型的元函数get_result_type
	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename T::template get_result_type<TUPLE> Impl;
		typedef typename Impl::result_type result_type;
	};
	
	// require 2:T的对象应该具备operator () 成员函数模板,用于求值
	template<typename... Arg>
	auto operator () (Arg... arg)->typename get_result_type<std::tuple<Arg...>>::result_type
	{
		return impl.template operator () (std::forward<std::tuple<TL...>>(t));
	}
	
	T impl;
};

template<typename T1, typename T2>
TExpr<TExprAdd<T1, T2> >
operator + (T1 a, T2 b)
{
	typedef TExprAdd<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}

template<typename T1, typename T2>
TExpr<TExprSub<T1, T2> >
operator - (T1 a, T2 b)
{
	typedef TExprSub<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}
 
 
 
 

这样就至关于描写叙述了一个TExpr接口,有若干个详细实现:TExprBasic。TExprAdd,TExprSub等。[在这里接口的描写叙述体现在TExpr对模板參数类型的依赖。要求T包括什么样的类型,要求T的对象有什么样的操做。接口的实现体现在把TExpr<...>做为TExpr的模板參数。]嗯。也就是表达式模板技术。ui

因而咱们的语法树中的-和+结点的类型分别变为:this

TExpr<TExprAdd<TExprBasic<0>, TExprBasic<1>>>和TExpr<TExprSub<TExprAdd<TExprBasic<0>, TExprBasic<1>>, TExprBasic<2>>>添加TExpr优势是,语法树中的结点被分为三类:TExpr<...>。TExprBasic<...>。以及其余。这三类结点要求能够计算返回类型,求值。

首先明白计算的输入和输出,返回类型的输入是变长模板參数,返回一个返回类型,求值的输入是tuple,返回一个值。而三种类型的编译时和执行时求值策略很是清楚:1. TExpr可以直接依赖于模板參数。计算返回值类型,求值。2. TExprBasic可以直接计算返回值类型(输入变长模板參数,返回该模板參数某个位置上的类型),直接求值(输入tuple,返回tuple中某一项)。 spa

3. 其余类型的计算返回值类型,求值方法就是自己的类型和值。code

因此可以很easy地针对这三类结点写出处理类。另外还有TExprAdd之类的类没有处理。这类结点的返回值类型计算需要分别计算其左操做数和右操做数的类型,然而在C++11中咱们可以方便地用decltype(TA()+TB())来进行处结果的类型推导。而求值也是分别计算左右操做数的值,而后中间填上一个相应的操做符,做为一个表达式返回。[另外。还可以把TExprBasic做为TExpr的參数,这样所有的结点类型仅仅剩下TExpr和其余类型了,更加方便管理。这个包装过程仅仅需要改改代码就能够。

只是不改也能体现出一种思想,TExpr是递归的。TExprBasic是原子的,其余类型是原子的。]在此基础上,还引入两类print函数。没有參数的能输出带占位符的语法树。有參数的能输出带不少其余信息的语法树。

#include <iostream>
#include <tuple>
#include <vector>
#include <algorithm>
using namespace std;

template<int v>
struct int_{enum{value=v};};

template<typename T>
struct value_of{enum{value=-1};};

template<int v>
struct value_of<int_<v>>{enum{value=v};};

template<typename V1, typename V2>
struct max_type
{
	template<typename VA, typename VB, bool>
	struct max_type_impl
	{
		typedef VA result_type;
	};
	template<typename VA, typename VB>
	struct max_type_impl<VA, VB, true>
	{
		typedef VB result_type;
	};
	enum{value1=value_of<V1>::value, value2=value_of<V2>::value};
	typedef typename max_type_impl<V1, V2, (value1<value2)>::result_type result_type;
};

template<typename T>
struct TExpr
{
	
	TExpr(T o) : v(o){}
	
	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename T::template get_result_type<TUPLE> Impl;
		typedef typename Impl::result_type result_type;
	};
	template<typename... Arg>
	auto operator () (Arg... arg)->typename get_result_type<std::tuple<Arg...>>::result_type
	{
		return this->template evalue(std::tuple<Arg...>(arg...));
	}
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)->typename get_result_type<std::tuple<TL...>>::result_type
	{
		return v.template evalue(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... Arg>
	void print(Arg... arg)
	{
		this->template print(tuple<Arg...>(arg...));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		v.template print(std::forward<std::tuple<TL...>>(t));
	}
	void print()
	{
		v.print();
	}
	T v;
};

template<int v>
struct TExprBasic
{
	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename std::tuple_element<v, TUPLE>::type result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)->typename get_result_type<std::tuple<TL...>>::result_type
	{
		return std::get<v>(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << std::get<v>(std::forward<std::tuple<TL...>>(t));
	}
	void print()
	{
		cout << v;
	}
};

template<typename T>
struct is_expr
{
	enum{value=false};
};
template<typename T>
struct is_expr<TExpr<T>>
{
	enum{value=true};
};
template<int v>
struct is_expr<TExprBasic<v>>
{
	enum{value=true};
};

template<typename T, typename TUPLE>
struct get_result_type
{
	typedef T result_type;
};
template<typename T, typename TUPLE>
struct get_result_type<TExpr<T>, TUPLE>
{
	typedef typename TExpr<T>::template get_result_type<TUPLE>::result_type result_type;
};
template<int v, typename TUPLE>
struct get_result_type<TExprBasic<v>, TUPLE>
{
	typedef typename TExprBasic<v>::template get_result_type<TUPLE>::result_type result_type;
};

template<typename T>
struct print_helper_t
{
	typedef int_<is_expr<T>::value> U;
	
	print_helper_t(T a) : x(a){}
	
	void print()
	{
		print_impl(U());
	}
	void print_impl(int_<1>)
	{
		x.print();
	}
	void print_impl(int_<0>)
	{
		cout << x;
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		print_impl(std::forward<std::tuple<TL...>>(t), U());
	}
	template<typename... TL>
	void print_impl(std::tuple<TL...>&& t, int_<1>)
	{
		x.print(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print_impl(std::tuple<TL...>&& t, int_<0>)
	{
		cout << x;
	}
	T x;
};
template<typename T>
print_helper_t<T> print_helper(T x)
{
	return print_helper_t<T>(x);
}

template<typename T, typename TUPLE>
struct value_helper_t
{
	typedef int_<is_expr<T>::value> U;
	typedef typename ::get_result_type<T, TUPLE>::result_type result_type;
	
	value_helper_t(T a) : x(a){}
	
	template<typename... TL>
	result_type value(std::tuple<TL...>&& t)
	{
		return value_impl(std::forward<std::tuple<TL...>>(t), U());
	}
	template<typename... TL>
	result_type value_impl(std::tuple<TL...>&& t, int_<1>)
	{
		return x.template evalue(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	result_type value_impl(std::tuple<TL...>&& t, int_<0>)
	{
		return x;
	}
	T x;
};
template<typename T, typename TUPLE>
value_helper_t<T, TUPLE> value_helper(T x)
{
	return value_helper_t<T, TUPLE>(x);
}

template<typename T1, typename T2>
struct TExprAdd
{

	TExprAdd(T1 a, T2 b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename ::get_result_type<T1, TUPLE>::result_type TA;
		typedef typename ::get_result_type<T2, TUPLE>::result_type TB;
		typedef decltype(TA()+TB()) result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)-> typename get_result_type<std::tuple<TL...>>::result_type
	{
		return value_helper<T1, std::tuple<TL...>>(x).template value(std::forward<std::tuple<TL...>>(t)) + 
			   value_helper<T2, std::tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << "(";
		print_helper(x).template print(std::forward<std::tuple<TL...>>(t));
		cout << " + ";
		print_helper(y).template print(std::forward<std::tuple<TL...>>(t));
		cout << ")";
	}
	void print()
	{
		cout << "(";
		print_helper(x).template print();
		cout << " + ";
		print_helper(y).template print();
		cout << ")";
	}
	T1 x;
	T2 y;
};

template<typename T1, typename T2>
struct TExprSub
{

	TExprSub(T1 a, T2 b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename ::get_result_type<T1, TUPLE>::result_type TA;
		typedef typename ::get_result_type<T2, TUPLE>::result_type TB;
		typedef decltype(TA()-TB()) result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)-> typename get_result_type<std::tuple<TL...>>::result_type
	{
		return value_helper<T1, std::tuple<TL...>>(x).template value(std::forward<std::tuple<TL...>>(t)) - 
			   value_helper<T2, std::tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << "(";
		print_helper(x).template print(std::forward<std::tuple<TL...>>(t));
		cout << " - ";
		print_helper(y).template print(std::forward<std::tuple<TL...>>(t));
		cout << ")";
	}
	void print()
	{
		cout << "(";
		print_helper(x).template print();
		cout << " - ";
		print_helper(y).template print();
		cout << ")";
	}
	T1 x;
	T2 y;
};

template<typename T1, typename T2>
struct TExprMul
{

	TExprMul(T1 a, T2 b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename ::get_result_type<T1, TUPLE>::result_type TA;
		typedef typename ::get_result_type<T2, TUPLE>::result_type TB;
		typedef decltype(TA()*TB()) result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)-> typename get_result_type<std::tuple<TL...>>::result_type
	{
		return value_helper<T1, std::tuple<TL...>>(x).template value(std::forward<std::tuple<TL...>>(t)) * 
			   value_helper<T2, std::tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << "(";
		print_helper(x).template print(std::forward<std::tuple<TL...>>(t));
		cout << "*";
		print_helper(y).template print(std::forward<std::tuple<TL...>>(t));
		cout << ")";
	}
	void print()
	{
		cout << "(";
		print_helper(x).template print();
		cout << "*";
		print_helper(y).template print();
		cout << ")";
	}
	T1 x;
	T2 y;
};

template<typename T1, typename T2>
struct TExprDiv
{

	TExprDiv(T1 a, T2 b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename ::get_result_type<T1, TUPLE>::result_type TA;
		typedef typename ::get_result_type<T2, TUPLE>::result_type TB;
		typedef decltype(TA()/TB()) result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)-> typename get_result_type<std::tuple<TL...>>::result_type
	{
		return value_helper<T1, std::tuple<TL...>>(x).template value(std::forward<std::tuple<TL...>>(t)) / 
			   value_helper<T2, std::tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << "(";
		print_helper(x).template print(std::forward<std::tuple<TL...>>(t));
		cout << "/";
		print_helper(y).template print(std::forward<std::tuple<TL...>>(t));
		cout << ")";
	}
	void print()
	{
		cout << "(";
		print_helper(x).template print();
		cout << "/";
		print_helper(y).template print();
		cout << ")";
	}
	T1 x;
	T2 y;
};

template<typename T1, typename T2>
struct TExprComma
{

	TExprComma(T1 a, T2 b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename ::get_result_type<T1, TUPLE>::result_type TA;
		typedef typename ::get_result_type<T2, TUPLE>::result_type TB;
		typedef TB result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)-> typename get_result_type<std::tuple<TL...>>::result_type
	{
		value_helper<T1, std::tuple<TL...>>(x).template value(std::forward<std::tuple<TL...>>(t));
		return value_helper<T2, std::tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << "(";
		print_helper(x).template print(std::forward<std::tuple<TL...>>(t));
		cout << " , ";
		print_helper(y).template print(std::forward<std::tuple<TL...>>(t));
		cout << ")";
	}
	void print()
	{
		cout << "(";
		print_helper(x).template print();
		cout << " , ";
		print_helper(y).template print();
		cout << ")";
	}
	T1 x;
	T2 y;
};

template<typename T1, typename T2>
struct TExprShiftLeft
{

	TExprShiftLeft(T1 a, T2 b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef typename ::get_result_type<T1, TUPLE>::result_type TA;
		typedef typename ::get_result_type<T2, TUPLE>::result_type TB;
		typedef TA result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)-> typename get_result_type<std::tuple<TL...>>::result_type
	{
		return value_helper<T1, tuple<TL...>>(x).template value(std::forward<std::tuple<TL...>>(t)) << 
			   value_helper<T2, tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		typedef typename get_result_type<tuple<TL...>>::result_type result_type;
		output("(", int_<std::is_integral<result_type>::value>());
		print_helper(x).template print(std::forward<std::tuple<TL...>>(t));
		cout << " << ";
		print_helper(y).template print(std::forward<std::tuple<TL...>>(t));
		output(")", int_<std::is_integral<result_type>::value>());
	}
	void print()
	{
		//output("(", int_<std::is_integral<result_type>::value>());
		print_helper(x).template print();
		cout << " << ";
		print_helper(y).template print();
		//output(")", int_<std::is_integral<result_type>::value>());
	}
	void output(const char* s, int_<1>)
	{
		cout << s;
	}
	void output(const char* s, int_<0>)
	{
	}
	T1 x;
	T2 y;
};

template<typename T>
struct TExprShiftLeft<ostream, T>
{
	TExprShiftLeft(ostream& a, T b) : x(a), y(b){}

	template<typename TUPLE>
	struct get_result_type
	{
		typedef ostream& result_type;
	};
	template<typename... TL>
	auto evalue(std::tuple<TL...>&& t)->typename get_result_type<std::tuple<TL...>>::result_type
	{
		return x << value_helper<T, tuple<TL...>>(y).template value(std::forward<std::tuple<TL...>>(t));
	}
	template<typename... TL>
	void print(std::tuple<TL...>&& t)
	{
		cout << "cout << ";
		y.print(std::forward<std::tuple<TL...>>(t));
	}
	void print()
	{
		cout << "xout << ";
		y.print();
	}
	ostream& x;
	T y;
};

template<typename T1, typename T2>
TExpr<TExprAdd<T1, T2> >
operator + (T1 a, T2 b)
{
	typedef TExprAdd<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}

template<typename T1, typename T2>
TExpr<TExprSub<T1, T2> >
operator - (T1 a, T2 b)
{
	typedef TExprSub<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}

template<typename T1, typename T2>
TExpr<TExprMul<T1, T2> >
operator * (T1 a, T2 b)
{
	typedef TExprMul<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}

template<typename T1, typename T2>
TExpr<TExprDiv<T1, T2> >
operator / (T1 a, T2 b)
{
	typedef TExprDiv<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}

template<typename T1, typename T2>
TExpr<TExprComma<T1, T2> >
operator , (T1 a, T2 b)
{
	typedef TExprComma<T1, T2> TI;
	return TExpr<TI>(TI(a, b));
}

template<typename T>
TExpr<TExprShiftLeft<ostream, TExpr<T> > >
operator << (ostream& out, TExpr<T> x)
{
	typedef TExprShiftLeft<ostream, TExpr<T>> TI;
	return TExpr<TI>(TI(out, x));
}

template<int T>
TExpr<TExprShiftLeft<ostream, TExprBasic<T> > >
operator << (ostream& out, TExprBasic<T> x)
{
	typedef TExprShiftLeft<ostream, TExprBasic<T>> TI;
	return TExpr<TI>(TI(out, x));
}

template<typename T1, typename T2>
TExpr<TExprShiftLeft<TExpr<T1>, T2>>
operator << (TExpr<T1> e, T2 x)
{
	typedef TExprShiftLeft<TExpr<T1>, T2> TI;
	return TExpr<TI>(TI(e, x));
}

template<int v, typename T1>
TExpr<TExprShiftLeft<TExprBasic<v>, T1>>
operator << (TExprBasic<v> e, T1 x)
{
	typedef TExprShiftLeft<TExprBasic<v>, T1> TI;
	return TExpr<TI>(TI(e, x));
}

#define MAKE(x) TExprBasic<x> _ ## x
MAKE(0);MAKE(1);MAKE(2);MAKE(3);MAKE(4);MAKE(5);MAKE(6);MAKE(7);MAKE(8);MAKE(9);

int main()
{
	auto add = _0 + _1;
	cout << add(string("123"), "456") << endl;
	cout << add((int*)0, 1) << endl;
	cout << add("12345678", 1) << endl;
	
	auto test = (cerr << ((_0 << _1) + _2 * 0 - _1 / _2) << "___" << _3 << "___" << (int*)&main, cerr << _0, 1);
	test.print();
	cout << endl;
	test.print(4, 5, 6, string("c++"));
	cout << endl << "=";
	test(4, 5, 6, "hello world");
	cout << endl;
	
	int init = 0;
	vector<int> vec(8);
	for_each(vec.begin(), vec.end(), [&](int& a){a=++init;});
	for_each(vec.begin(), vec.end(), cout << _0);
	return 0;
}
相关文章
相关标签/搜索