function object研究之五

来源:互联网 发布:apache calcite 中文 编辑:程序博客网 时间:2024/06/04 09:48

巧妙的检测占位符

boost提供了从_1到_9的占位符,它们是9个变量。这些变量本质上都是一个模板类的实例化对象,特殊之处在于这个模板类arg<> 只接收1-9 的整数作为模板参数。下面详细介绍如何检测模板参数,并且当模板参数不符合要求时如何做到编译报错。

具体定义如下:

boost::arg<1> _1;boost::arg<2> _2;boost::arg<3> _3;boost::arg<4> _4;boost::arg<5> _5;boost::arg<6> _6;boost::arg<7> _7;boost::arg<8> _8;boost::arg<9> _9;template< int I > struct arg{    arg()    {    }    template< class T > arg( T const & /* t */ )    {        // static assert I == is_placeholder<T>::value        typedef char T_must_be_placeholder[ I == is_placeholder<T>::value? 1: -1 ];    }};template< int I > bool operator==( arg<I> const &, arg<I> const & ){    return true;}template< int I > struct is_placeholder< arg<I> >{    enum _vt { value = I };};template< int I > struct is_placeholder< arg<I> (*) () >{    enum _vt { value = I };};template< class T > struct is_placeholder{    enum _vt { value = 0 };};

说明:

1. arg<>模板类有两个构造函数,默认构造函数在运行时调用。模板构造函数在编译时被调用,它才是真正接受了1-9整数参数的函数。但是为什么class T居然是arg<1>类型,现在还不知道原因。

2.is_placeholder在这里做了分析http://blog.csdn.net/sheismylife/article/details/8268644

3.利用数组的初始化长度不能小于0,来做编译期检测。

typedef char T_must_be_placeholder[ I == is_placeholder<T>::value? 1: -1 ];
这句话首先用了一个char数组,数组名字的意思就是 T必须是一个placeholder。placeholder就是arg<1>到arg<9>这9个全局变量,或者写成_1到_9.

如果将_1或者_9作为参数构造boost::arg对象,编译会通过。因为is_placeholder<_1>::value的值肯定是1,再和I比较,I本来也是1,因此I==is_placeholder<T>::value的结果是true,最终数组长度为1.

但是如果传递的是_1到_9之外的参数,数组长度为-1. 编译器会报错:

boost::arg<1> arg1(_1);//编译通过,因为_1是占位符string str;boost::arg<1> arg2(str);//编译不通过,因为str不是占位符


/usr/src/boost_1_47_0/boost/bind/arg.hpp: In constructor ‘boost::arg<I>::arg(const T&) [with T = std::basic_string<char>, int I = 1]’:In file included from /usr/src/boost_1_47_0/boost/bind/bind.hpp:29:0, from /usr/src/boost_1_47_0/boost/bind.hpp:22, from main.cpp:12:main.cpp:59:27: instantiated from here/usr/src/boost_1_47_0/boost/bind/arg.hpp:37:22: error: size of array is negative

这也说明==,?:操作符都是可以在编译期间求值