回 帖 发 新 帖 刷新版面

主题:[原创]『C++Boost』赋值(Assignment)库(一)

Assignment 库

来源::[url=http://dozb.blogchina.com/1685363.html]http://dozb.blogchina.com/1685363.html[/url]  

译者:[url=http://dozb.blogchina.com/]dozb[/url]
英文版: [url=http://www.boost.org/libs/assign/doc/index.html]英文版[/url]

Copyright ? 2003-2004 Thorsten Ottosen

使用,修改和分发要服从Boost的软件许可, 版本1.0 (见 http://www.boost.org/版权_1_0.txt).

内容列表
入门
指南
函数 operator+=()
函数 operator()()
函数 list_of()
函数 map_list_of()
函数 repeat() 和 repeat_fun()
一个 "复杂些的" 例子

--------------------------------------------------------------------------------

入门
这里展现了为数不多的operator,()的实践.
Bjarne Stroustrup, C++ 的设计和发展者

这个库的目的是通过重载operator,() 和 operator()()来方便地向容器填充数据。有两种操作方式能构造一系列值,然后复制到容器中:

逗号分割的列表:

vector<int> v;
v += 1,2,3,4,5,6,7,8,9;
 

括号分割的列表:
map<string,int> m;
insert( m )( "Bar", 1 )( "Foo", 2 );
这些系列值在学习、测试和建模中经常需要的,而且也是方便使用的。这个库和标准库容器预定的操作紧密相关,但是大多功能也能和标准兼容的容器一起工作。这个库也可以扩展到用户定义的类型,例如,可以在一系列参数值中,调用一个成员函数代替正常的参数值。


--------------------------------------------------------------------------------

指南
两分钟内你就会用这些库。主要组成分解如下:

函数 operator+=()
函数 operator()()
函数 list_of()
函数 map_list_of()
函数 repeat() 和 repeat_fun()
A "复杂的" 例子
在创建容器对象后,下面前两个函数用于继续增加元素,后两个函数用于需要清空容器后再增加元素。

 

函数 operator+=()可定制 ),使用operator()()是非常方便的。这对于序列容器也适用:
通过operator+=()用数据填充vector(或任何标准容器),可以这么写

#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/assert.hpp>;
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope

{
    vector<int> values;  
    values += 1,2,3,4,5,6,7,8,9; // 插入值到容器的末尾
    BOOST_ASSERT( values.size() == 9 );
    BOOST_ASSERT( values[0] == 1 );
    BOOST_ASSERT( values[9] == 9 );
}
这里我们仅仅填充常量到容器,但是可以用任意表达式组成序列,只要每个表达式的结果能转换成容器的值类型就行。

 

函数 operator()()
我们不能直接调用operator()() ,但是可以调用一个函数,其返回值是定义了operator()()的代理对象。返回的代理对象的函数总是被指定在成员函数之后,用来复制序列中的值到容器中。因此通过pair值填充map,你能如下写
 

#include <boost/assign/list_inserter.hpp> // for 'insert()'
#include <boost/assert.hpp>
#include <string>
using namespace std;
using namespace boost::assign; // bring 'insert()' into scope

{
    map<string,int> 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 );
    BOOST_ASSERT( m.size() == 12 );    
    BOOST_ASSERT( m["january"] == 31 );
}
当我们需要用多个参数构造对象(缺省等于五个参数,但这个大小

#include <boost/assign/list_inserter.hpp> // for 'push_front()'
#include <boost/assert.hpp>
#include <string>
#include <utility>
using namespace std;
using namespace boost::assign; // bring 'push_front()' into scope

{
    typedef pair< string,string > str_pair;
    deque<str_pair> deq;
    push_front( deq )( "foo", "bar")( "boo", "far" );
    BOOST_ASSERT( deq.size() == 2 );
    BOOST_ASSERT( deq.front().first == "boo" );
    BOOST_ASSERT( deq.back().second == "bar" );
}   
除了push_front() ,我们也可以用push_back(),前提是容器有相应的成员函数。空括号能被用于插入缺省的构造对象,例如,push_front( deq )()() 将插入两个缺省构造的str_pair对象。

 

假如operator()()使用起来特别烦琐,例如push_front()我们也可以这么写

deque<int> di;    
push_front( di ) = 1,2,3,4,5,6,7,8,9;
BOOST_ASSERT( di.size() == 9 );    
BOOST_ASSERT( di[8] == 9 );    

直截了当,上面的代码在标准容器中不受限制,而且也工作于所有用右成员函数的标准兼容的容器。仅仅operator+=()限制在标准容器中使用。

函数 list_of() array ,请看所支持的库列表。
但是假如我们需要初始化容器怎么做?这就要引出list_of() 。用list_of() 我们能创建匿名列表来自动转换给任何容器:

#include <boost/assign/list_of.hpp> // for 'list_of()'
#include <boost/assert.hpp>
#include <list>
#include <stack>
#include <string>
using namespace std;
using namespace boost::assign; // bring 'list_of()' into scope

{
    const list<int> primes = list_of(1)(2)(3)(5)(7)(11);
    BOOST_ASSERT( primes.size() == 6 );
    BOOST_ASSERT( primes.back() == 11 );
    BOOST_ASSERT( primes.front() == 1 );
   
    const stack<string> names = list_of( "Mr. Foo" )( "Mr. Bar")( "Mrs. FooBar" ).to_adapter();
    const stack<string> names2 = (list_of( "Mr. Foo" ), "Mr. Bar", "Mrs. FooBar" ).to_adapter();
    BOOST_ASSERT( names.size() == 3 );
    BOOST_ASSERT( names[0] == "Mr. Foo" );
    BOOST_ASSERT( names[2] == "Mrs. FooBar" );
}   
假如我们需要初始化一个容器适配器(adapter),我们需要调用to_adapter()告诉编译器。第二个例子说明了这一点,对于list_of(),我们能用一个逗号分割的序列,然后把to_adapter()放入整个右手边。 需要注意的是list_of()的第一个参数决定匿名序列的类型。在这个stack中,由const char* 对象组成的匿名序列被转换到stack的string对象。只要两种类型可转,这种转换总是可行的。

 

请注意list_of() 能转换成 boost::

函数 map_list_of()
这个函数和map一起使用,非常方便。他的用法比较简单:

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/assert.hpp>
#include <map>
using namespace std;
using namespace boost::assign; // bring 'map_list_of()' into scope

{
    map<int,int> next = map_list_of(1,2)(2,3)(3,4)(4,5)(5,6);
    BOOST_ASSERT( next.size() == 5 );
    BOOST_ASSERT( next[ 1 ] == 2 );
    BOOST_ASSERT( next[ 5 ] == 6 );
    
    // or we can use 'list_of()' by specifying what type
    // the list consists of
    next = list_of< pair<int,int> >(6,7)(7,8)(8,9);
    BOOST_ASSERT( next.size() == 3 );
    BOOST_ASSERT( next[ 6 ] == 7 );
    BOOST_ASSERT( next[ 8 ] == 9 );      
}   
函数 repeat() 和 repeat_fun()
有时候多次重复同样的值令人恼火,这就是repeat()能发挥作用的地方:

#include <boost/assign/list_of.hpp>
#include <boost/assign/std/vector.hpp>
#include <boost/assert.hpp>

using namespace std;
using namespace boost::assign;

{
    vector<int> v;
    v += 1,2,3,repeat(10,4),5,6,7,8,9;
    // v = [1,2,3,4,4,4,4,4,4,4,4,4,4,5,6,7,8,9]
    BOOST_ASSERT( v.size() == 3 + 10 + 5 );
    
    v = list_of(1).repeat(5,2)(3);
    // v = [1,2,2,2,2,2,3]
    BOOST_ASSERT( v.size() == 1 + 5 + 1 );
    
    push_back( v )(1).repeat(1,2)(3);
    // v = old v + [1,2,3]
    BOOST_ASSERT( v.size() == 10 );
}
我们能看到,repeat()是重复“第二个参数”“第一个参数”次。

 

更普遍的情况能用repeat_fun()来构造:

#include <boost/assign/std/vector.hpp>
#include <boost/assert.hpp>
#include <cstdlib> // for 'rand()'              

using namespace std;
using namespace boost::assign;

template< class T >
struct next    
{
    T seed;
    next( T seed ) : seed(seed)
    { }
    
    T operator()() const
    {
        return seed++;
    }
};
     
{
    vector<int> v;
    v += 1,2,repeat_fun(4,&rand),4;
    // v = [1,2,?,?,?,?,4]
    BOOST_ASSERT( v.size() == 7 );
    
    push_back( v ).repeat_fun(4,next<int>(0))(4).repeat_fun(4,next<int>(5));
    // v = old v + [0,1,2,3,4,5,6,7,8]
    BOOST_ASSERT( v.size() == 16 );
}        
对repeat_fun()来说,第二个参数要求是一个无参函数。

 

一个 "复杂一些的" 例子
在最后例子中,让我们假设,我们需要保持跟踪足球赛的结果。一个队赢了就记一分,输了就记零分。假如每个组经过了三场比赛,代码如下:

#include <boost/assign/list_of.hpp>
#include <boost/assign/list_inserter.hpp>
#include <boost/assert.hpp>
#include <string>
#include <vector>

using namespace std;
using namespace boost::assign;

{
    typedef vector<int>                   score_type;
    typedef map<string,score_type>        team_score_map;
    typedef pair<string,score_type>       score_pair;

    team_score_map group1, group2;
    
    //
    // method 1: using 'insert()'
    //
    insert( group1 )( "Denmark", list_of(1)(1) )
                    ( "Germany", list_of(0)(0) )
                    ( "England", list_of(0)(1) );
    BOOST_ASSERT( group1.size() == 3 );
    BOOST_ASSERT( group1[ "Denmark" ][1] == 1 );
    BOOST_ASSERT( group1[ "Germany" ][0] == 0 );
    
    //
    // method 2: using 'list_of()'
    //
    group2 = list_of< score_pair >
                        ( "Norway",  list_of(1)(0) )
                        ( "USA",     list_of(0)(0) )
                        ( "Andorra", list_of(1)(1) );
    BOOST_ASSERT( group2.size() == 3 );
    BOOST_ASSERT( group2[ "Norway" ][0] == 1 );
    BOOST_ASSERT( group2[ "USA" ][0] == 0 );
}
    
在第一个例子中,注意list_of()的结果如何自动转换到vector去的,因为insert()知道他所期望的是vector。在第二个例子中,list_of()没有那么聪明,因为这里它需要明确知道预期的参数。(将来可能会引进更加聪明的list_of())。

 

这就是所有的。现在你准备好用这个库了吧。

回复列表 (共20个回复)

沙发

好东西! 楼主贴个operator,的实作出来看看?

板凳

我也在学习中啊。学好后再发,嘿嘿。

3 楼

我意思是说operator+=的源码:
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 );
    }

4 楼

//修改了一点,试了试, 嘿! 比STL简单多了,^-^
#include <iostream>
#include <boost/assign/std/vector.hpp> // for 'operator+=()'
#include <boost/assert.hpp>
using namespace std;
using namespace boost::assign; // bring 'operator+=()' into scope

int main ()
{
    vector<int> values;  
    values += 1,2,3,4,5,6,7,8,9; // 插入值到容器的末尾
    BOOST_ASSERT( values.size() == 9 );
    BOOST_ASSERT( values[0] == 1 );
    //BOOST_ASSERT( values[9] == 9 );

    vector<int>::iterator i;
    for(i=values.begin(); i!=values.end(); i++)
        cout << *i << endl;

    return 0;
}

5 楼

哈哈,好。不错。

6 楼

boost的头文件怎么使用? boost是对stl的扩展,那么它也应该包含STL的有关头文件.有关boost的头文件boost库是怎样描述的?
#include <boost/assign/std/vector.hpp>应该包含有STL的vector头文件, 那如果我要实现如: deque \ list \ stack等,是应该要包含什么头文件?
不是这样吗?
  #include <boost/assign/std/deque.hpp>
  #include <boost/assign/std/list.hpp>          
  #include <boost/assign/std/stack.hpp>
例子中:
  #include <boost/assign/list_inserter.hpp>
  不用包含: list.hpp?

7 楼

这篇文章的后半部分我没有翻译,你可以看英文版的就明白了。因为它自己已经包含<list>了,它也要用呀,不包含怎么行?

8 楼

你的blog那有吗?

9 楼

后面的我还没有翻译完。因为后面的是具体实现了。

10 楼

仿函数?????
老实说翻译的很“烂”,也许我不该这样说。
好,给你鼓励!!!!!!!
加油!!!!!!
另:
我觉得Boost很强大,很不实用没有STL好,它只是一个后备的库,许多东西还不成熟。
(这只是我个人的意见!)

我来回复

您尚未登录,请登录后再回复。点此登录或注册