主题:[原创]『C++Boost』赋值(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())。
这就是所有的。现在你准备好用这个库了吧。