分析源码其实很有意思,尤其是优秀的源码。boost::assign库,老实说,设计初衷有些无聊,它无非是想让容器的赋值(插入)操作更加简单,简单得就像脚本语言一样,比如,原来的STL里的容器有各种各样的,不同的容器会有不同的赋值方式,比如: #include<vector>using namespace std:int main(){ vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); return 0;} 如果你不觉得敲‘.push_back’多么麻烦,大可不必管这个库,实际上这样写,机器看起来更简单。而boost就想办法让人偷懒,而机器转一些弯,成了这样: int main(){ vector<int> v; v+=1,2,3; return 0;} 能够运行的示范代码我没有找到啊,只是写个样子出来,OMG,真像脚本语言!你要问,效率如何?可能会牺牲一些,就像,我问你,仿函数比函数的调用效率是不是低一些,如果是,那STL里还不是大量用仿函数?但这些差别,绝对不是相差很大,不会有质的差别。 好了,下面进行分析,我不是设计者,不知道大哥他是怎么想的,我只从分析的角度说明。 1,设计各种仿函数来管理具体的容器和它的赋值方法 仿函数比函数好的一个地方,它可以有成员变量,而这里就关联了这个具体的容器。在源码的assign/list_inserter.hpp里的前面部分,有一个namespace assign_detail命名空间,在那里定义了各种,仿函数,比如调用push_back的 template< class C > class call_push_back { C& c_; public: call_push_back( C& c ) : c_( c ) { } template< class T > void operator()( T r ) { c_.push_back( r ); } }; 调用insert的 template< class C > class call_insert { C& c_; public: call_insert( C& c ) : c_( c ) { } template< class T > void operator()( T r ) { c_.insert( r ); } }; 那个大C表示容器Container,看到成员c了没有,在那里关联了外面的具体容器,它是一个引用,所以没有进行低效的复制操作,只是一个关联。operator()是调用函数,它简单的指向不同容器的具体赋值操作。 2,重载各种符号运算 再下来,外面是一个封装,类list_inserter,它是一个核心类,它关联一个具体的赋值仿函数对象,同时,重载了一些简单的操作符,比如operator, operator()等。一但成功建立了一个list_inserter,后面的赋值就可以用一些简单的符号进行了。它的样子是这样的: template< class Function, class Argument = assign_detail::forward_n_arguments > class list_inserter { ... private: list_inserter& operator=( const list_inserter& ); Function insert_; } 它关联一个赋值仿函数对象,具体的操作由它来完成,然后你会看到,各种各样的操作,比如operator,都是用insert_()来完成的,那个拷贝函数设成私有,就是用来禁止拷贝的,如果用户拷贝会有一个权限错误,不能访问私有成员,如果类本身访问,会有一个连接错误,总之是不能拷贝,当然那个insert_也不能,同样,具体的容器也就没有拷贝。 list_inserter是怎么建立起来的,它需要一些外部的函数来完成,这些函数是和具体的容器相关的,所以需要为每种容器写一份,在assign/std/目录里就是各种这样的定义,如vector.hpp里有简单这样几行: namespace boost{namespace assign{ template< class V, class A, class V2 > inline list_inserter< assign_detail::call_push_back< std::vector<V,A> >, V > operator+=( std::vector<V,A>& c, V2 v ) { return push_back( c )( v ); } }} (只例关键的),那是一个重载的operator+=,左边是一个V类型A分配器的vector,右边是一个V2类型的值,它具体是由push_back函数完成,你看到它这样写push_back(c)(v),实际上是先调用了push_back(c),它返回了一个list_inserter,再后面的(v),是将v插入进去,看push_back()定义: template< class C > inline list_inserter< assign_detail::call_push_back<C>, BOOST_DEDUCED_TYPENAME C::value_type > push_back( C& c ) { static BOOST_DEDUCED_TYPENAME C::value_type* p = 0; return make_list_inserter( assign_detail::call_push_back<C>( c ), p ); } 它果然返回的是一个list_inserter,插入仿函数是call_push_back,每二个参数是容器元素类型,每个容器内都要定义一个value_type,那个BOOST_DEDUCED_TYPENAME我猜就是typename,说明一个内嵌类型,那个static定义,也没有为多次调用push_back带来任何负担,再转调用make_list_inserter(),看它的定义: template< class Function, class Argument > inline list_inserter<Function,Argument> make_list_inserter( Function fun, Argument* ) { return list_inserter<Function,Argument>( fun ); } 它有两个形式,这只是其中一个,有元素类型的定义,那个传进来的Argument* p没有任何用,只是做一个类型推导,用仿函数对象fun初始化list_inserter,看到这里没有引用返回,list_inserter只是不能拷贝,但是可以拷贝构造。所以push_back( c )最终得到的、具现出的结果是:list_inserter<assign_detail::call_push_back<vector<int>>,int>( assign_detail::call_push_back<vector<int>>(v) ) 再调用list_inserter的operator(),它转调用的是insert_(),即用assign_detail::call_push_back<vector<int>>的operator()将初值插入到了容器。 总的看一下list_inserter支持多少种操作符重载(下面都是list_inserter的成员函数): list_inserter& operator()() { insert_( Argument() ); return *this; } template< class T > list_inserter& operator=( const T& r ) { insert_( r ); return *this; } template< class T > list_inserter& operator=( assign_detail::repeater<T> r ) { return operator,( r ); } template< class Nullary_function > list_inserter& operator=( const assign_detail::fun_repeater<Nullary_function>& r ) { return operator,( r ); } template< class T > list_inserter& operator,( const T& r ) { insert_( r ); return *this; } template< class T > list_inserter& operator,( const assign_detail::repeater<T> & r ) { return repeat( r.sz, r.val ); } template< class Nullary_function > list_inserter& operator,( const assign_detail::fun_repeater<Nullary_function>& r ) { return repeat_fun( r.sz, r.val ); } template< class T > list_inserter& repeat( std::size_t sz, T r ) { std::size_t i = 0; while( i++ != sz ) insert_( r ); return *this; } template< class Nullary_function > list_inserter& repeat_fun( std::size_t sz, Nullary_function fun ) { std::size_t i = 0; while( i++ != sz ) insert_( fun() ); return *this; } template< class SinglePassIterator > list_inserter& range( SinglePassIterator first, SinglePassIterator last ) { for( ; first != last; ++first ) insert_( *first ); return *this; } template< class SinglePassRange > list_inserter& range( const SinglePassRange& r ) { return range( boost::begin(r), boost::end(r) ); } template< class T > list_inserter& operator()( const T& t ) { insert_( t ); return *this; } 主要是operator,,它完成插入,还有operator()(T&),另外operator()()是插入一个临时元素,相当于空一位,此外还有几个帮助函数,assign_detail::repeater<T>和assign_detail::fun_repeater<Fun>,它们的作用很简单,可以帮助插入多个相同元素,或用一个函数构造多个元素,我们可以使用namespace assign里的repeat和repeat_fun来完成。 另外,还有一个mpl里的东西,那个if_c,其实可以找到他的定义,因为mpl库很大,不好说太多,那句是这样的: typedef BOOST_DEDUCED_TYPENAME mpl::if_c< is_same<Argument,assign_detail::forward_n_arguments>::value, n_arg_type, single_arg_type >::type arg_type; is_same<>是type_traits库里的,用来测试那两个类型是否相同,如果相同value==true,否则value==false,而if_c里定义的type,对第一个参数有特化版,如果true则type==第二个参数,否则type==第三个参数,它就像我们以前的if-else一样,只不过是在编译期做的判断。 最后,马上要过年啦,2008新春快乐! rickone 2008/2/5

评论