Boost源码剖析之:容器赋值-assign

来源:互联网 发布:网络购物用户规模 编辑:程序博客网 时间:2024/06/14 22:12

相信大多数使用STL的人都是为了使用里面的容器,使用vector、list、map的程序员对以下代码可以说是非常熟悉了:

vector i_v;i_v.push_back(1);i_v.push_back(2);i_v.push_back(3);i_v.push_back(4);i_v.push_back(5);

挺枯燥,是吧?用boost的assignment库可以让这一过程简洁得多:

#include "boost/assign/std/vector.hpp"using namespace boost::assign;vector i_v;i_v += 1,2,3,4,5;

效果与上面的程序一致,可读性却好很多,看上去有点“脚本语言”的感觉了。
对于关联容器,也有类似的便洁方法:

#include "boost/assign/list_inserter.hpp"#include "string"using namespace std;using namespace boost::assign;map months;insert( months )( "january", 31 )( "february", 28 )( "march", 31 )( "april", 30 )( "may", 31 )( "june", 30 )( "july", 31 )( "august", 31 )( "september", 30 )( "october", 31 )( "november", 30 )( "december", 31 );

分析assign的源代码,以vector为例,先看:

//assign/std/vector.hpp:template< class V, class A, class V2 >inline list_inserter< assign_detail::call_push_back< std::vector >, V >operator+=( std::vector & c, V2 v ){        return push_back( c )( v );}

操作符+=已被重载,它的任务是返回一个list_inserter类,这是assign中的核心类之一。再看push_back,它也没有实质性的动作,只是创建一个list_inserter然后返回它。

template< class C >inline list_inserter< assign_detail::call_push_back ,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 ), p );}

这里的call_push_back(c)实际是创建一个类call_push_back的实例,以使生成的list_inserter能够知道自己该怎样进行操作。

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 );        }};

make_list_inserter和STL中的make_pair类似,都是用于包装实现类的,真正的实现是利用list_inserter。

template< class Function, class Argument >inline list_inserter<Function,Argument>make_list_inserter( Function fun, Argument* ){        return list_inserter<Function,Argument>( fun );}

list_inserter重载了+=操作符,所以才有 i_v+=1,2,3,4,5 这种写法。可以看出 push_back函数返回一个list_inserter,对应例子,i_v+=1变为push_back(i_v)(1),其中的push_back(i_v) (注意:不包括后面的“(1)”!) 变为make_list_inserter(call_push_back(i_v), 0),最后make_list_inserter返回的是list_inserter< call_push_back, int>实例,现在可以加上后面的“(1)”了,由于list_inserter重载了“()”操作符,所以此时值1才被list_inserter接收。
那数字间的逗号又是怎么处理的呢?大家还记不记得 std::cout<< 1 << 2 << 3; 此处的<<和assign中的逗号其实是一个道理,<<操作符返回一个iostream,而逗号操作符返回一个 list_inserter 。“+=”操作符返回第一个list_inserter,其它的逗号“跟进”:

template< class Function, class Argument = assign_detail::forward_n_arguments >class list_inserter{        list_inserter( Function fun ) : insert_( fun )        {}                ....                list_inserter& operator()()        {                insert_( Argument() );                return *this;        }                template< class T >        list_inserter& operator,( const T& r )        {                insert_( r );                return *this;        }                private: Function insert_;}

这里的insert_就是先前的assign_detail::call_push_back ( c ),所以insert_( r )就是 assign_detail::call_push_back ( c )( r )。
list_inserter还有repeat,repeat_fun,range等方法,分别对应assign中 i_v+=1,repeat(2,4),3....等写法的实现。针对vector的assign基本就是这样,至于map等其它容器的assign,实现与此类似。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机屁股坏了怎么办 包颈手术后睡中会勃起怎么办 武警义务兵训练不合格怎么办 空姐体检心率不齐怎么办 空姐体检差身高怎么办 锻炼过猛肌肉疼怎么办 中考体检有问题怎么办 想参军视力不够怎么办 公司体检查出乙肝怎么办 乙肝携带者福利体检怎么办 小孩没考好我该怎么办 客户考虑我该怎么办 明天中考 我该怎么办 考试考差了怎么办 没考上理想高中怎么办 我是差学生中考怎么办 衬衫后背鼓起来怎么办 高考体检表没了怎么办 高考体检视力不合格怎么办 高考体检转氨酶高怎么办 高考体检肝功能异常怎么办 高考体检有乙肝怎么办 高考体检有纹身怎么办 学校体检血压高怎么办 高考体检不属实怎么办 艺考身上有花臂怎么办 义务兵因病致残怎么办 新兵练成绩优秀怎么办 阿提拉部队得了瘟疫怎么办 公安体能测评胖子怎么办 社区工作者笔试不及格怎么办 警察考核体能差怎么办 胖子跑步跑不动怎么办 电脑跑不动了怎么办 在部队体能不好怎么办 自考考试没过怎么办 没工作怎么办日本签证 毕业证被扣了怎么办 毕业证被撕了怎么办 中专的学历认证怎么办 搬宿舍东西多怎么办