assign:
许多情况下我们都需要为容器初始化或者赋值,填入大量的数据,比如初始错误代码和错误信息,或者是一些测试用的数据。STL容器仅提供了容纳这些数据的方法,但填充的步骤却是相当地麻烦,必须重复调用insert()或者push_back()等成员函数,这正是boost.assign出现的理由.
assign库重载了赋值操作符,operator+=,逗号操作符operator,和括号操作符operator(),可以用难以想象的简洁语法非常方便地对STL容器赋值或者初始化,在需要填入大量初值的地方很有用。
#include <boost/assign.hpp>
using namespace boost::assign;
使用操作符 +=向容器增加元素
boost.assign,由于重载了操作符+=和逗号,可以用简洁到令人震惊的语法完成原来用许多代码才能完成的工作。
使用assign库时必须使用using指示符,只有这样才能让重载的+=,等操作符在作用域内生效
示例:
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;//启用assign库的功能
vector<int> v; //标准向量容器
v += 1, 2, 3, 4, 5, 6, 7*8; //用operator+=和,填入数据
set<string> s; //标准集合容器
s += "cpp", "java", "c#", "python";
map<int, string> m;
m += make_pair(1, "one"), make_pair(2, "two");
system("pause");
return 0;
}
元素不一定是常量,表达式或者函数调用也是可以接受的,只要结果能够转换成容器可容纳的类型。比较特别的是map容器,必须用make_pair()辅助函数来生成容器元素,单纯地用括号把pair的两个成员括起来是无效的。
operator+=很好用,但它仅应用与stl中定义的标准容器(vector,list,set等),对于其他类型的容器(如boost新容器)则无能为力.
使用操作符()向容器增加元素:
operator+=使用上有些小的限制,而且在处理map容器也显麻烦,assign库使用操作符operator()提供更通用的解决方案。
我们不能直接使用operator(),而应当使用assign库提供三个辅助函数insert(),push_front(),push_back().这些函数可作用于拥有同名成员函数的容器,接受容器变量作为参数,返回一个代理对象list_inserter,它重载了operator(),=等操作符用来实现向容器填入数据的功能。
示例:
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;//启用assign库的功能
vector<int> v; //标准向量容器
push_back(v)(1)(2)(3)(4); //使用push_back辅助函数
list<string> l;
push_front(l)("cpp")("java")("c#")("python"); //使用push_front辅助函数
set<double> s;
insert(s)(3.14)(3.15)(3.16)(3.17); //使用insert辅助函数
map<int, string> m;
insert(m)(1, "one")(2, "two");
system("pause");
return 0;
}
operator()的好处是可以在括号中使用多个参数,这对于map这样的元素是由多个值组成类型非常方便,避免了make_pair()函数的使用,而且,如果括号中没有参数,那么将调用容器元素的缺省构造函数填入一个缺省值,逗号操作符则不能这样做。
括号操作符也可以与逗号等操作符配合使用,写法更简单:
using namespace boost::assign;
vector<int> v;
push_back(v),1,2,3,4,5;
push_back(v)(6),7,6,4,2;
deque<string> d;
push_front(d)() = "cpp","java","c#","python";
assert(d.size() == 5);
初始化容器元素:
操作符+=和()解决了对容器的赋值问题,但有的时候需要在容器构造的时候就完成数据的填充,这种方式较赋值更为高效。c++内建的数组和标准字符串类string支持这样做,但stl容器则不行。
assign库使用list_of(),map_list_of()/pair_list_of()和tuple_list_of()三个函数解决了这个问题.
list_of:
list_of()函数的用法与之前的insert(),push_back()等函数很相似,也重载了括号,逗号操作符。它很智能,返回一个匿名的列表,可以赋值给任意容器。
示例:
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;//启用assign库的功能
vector<int> v = list_of(1)(2)(3)(4)(5);
deque<string> d = (list_of("power")("bomb"),("phazon"),("suit")); //注意括号的使用
set<int> s = (list_of(10),20,30,50);
map<int, string> m = list_of(make_pair(1, "one"))(make_pair(2, "two"));
system("pause");
return 0;
}
list_of()函数可以全部使用括号操作符,也可以把括号与逗号结合起来,但使用后者时需要将整个list_of表达式用括号括起来,否则会使编译器无法推导出list_of的类型而无法赋值.
map_list_of/pair_list_of
使用list_of()处理map容器不是很方便,于是map_list_of()/pair_list_of()应运而生,map_list_of()可以接受两个参数,然后自动构造std::pair对象插入map容器,pair_list_of()则纯粹是map_list_of的同义词,两者的用法功能完全相同.
#include <map>
#include <set>
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;//启用assign库的功能
map<int, int> m1 = map_list_of(1, 2)(3, 4)(5, 6);
map<int, string> m2 = map_list_of(1, "one")(2, "two");
system("pause");
return 0;
}
tuple_list_of:
tuple_list_of用于初始化元素类型为tuple的容器,tuple是boost引入的一种新的容器/数据结构
减少重复输入:
assign库提供repeat(),repeat_fun()和range()三个函数来减少重复的输入;
repeat()函数把第二个参数作为要填入的值,重复第一个参数指定的次数,与vector,deque等容器的构造函数很相似,repeat_fun()函数同样重复第一个参数的次数,但第二个参数是个无参的函数或函数对象,它返回填入的数值;range()函数则可以把一个序列全部或部分元素插入到另一个序列里。
示例;
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <cstdlib> //for rand()
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;//启用assign库的功能
vector<int> v = list_of(1).repeat(3, 2)(3)(4)(5);
// v = 1,2,2,2,3,4,5
multiset<int> ms;
insert(ms).repeat_fun(5, &rand).repeat(2, 1), 10;
// ms = x,x,x,x,x,1,1,10
deque<int> d;
push_front(d).range(v.begin(), v.begin() + 5);
// d = 3,2,2,2,1
system("pause");
return 0;
}
与非标准容器工作:
assign库不仅支持全部八个STL标准容器(vector,string,deque,list,set,multiset,map,multimao),也对STL中的容器适配器提供了适当的支持,包括stack,queue和priority_queue.
因为stack等容器适配器不符合容器的定义,没有insert,push_back等成员函数,所以不能使用赋值的方式填入元素,只能使用初始化的方式,并在list_of表达式最后使用to_adapter()成员函数来适配到非标准容器。如果使用逗号操作符还需要把整个表达式用括号括起来,才能使用点号调用to_adapter().
示例:
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <cstdlib> //for rand()
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;
stack<int> stk = (list_of(1), 2, 3).to_adapter();
while(!stk.empty())//输出stack的内容
{
cout<<stk.top()<<" ";
stk.pop();
}
cout<<endl;
queue<string> q = (list_of("China")("US")("UK")).repeat(2, "russia").to_adapter();
while(!q.empty())//输出queue的内容
{
cout<<q.front()<< " ";
q.pop();
}
cout <<endl;
priority_queue<double> pq = (list_of(1.414), 1.732, 2.236).to_adapter();
while(!pq.empty())//输出优先队列的内容
{
cout<< pq.top()<< " ";
pq.pop();
}
system("pause");
return 0;
}
assign库也支持部分不在STL中定义的非标准容器,如STLport中的slist和hash_set/hash_map。
示例:
#include <slist> //非标准的单向链表
#include <hash_map> //非标准的散列映射容器
#include <string>
#include <boost/assign.hpp>
#include <boost/optional.hpp>
#include <boost/utility/in_place_factory.hpp>
#include <cstdlib> //for rand()
using namespace boost;
using namespace std;
int main()
{
using namespace boost::assign;
//slist<int> sl;
//push_front(sl), 1, 2, 3, 4, 5;
hash_map<string, int> hm = map_list_of("one", 1)("two", 2);
system("pause");
return 0;
}
此外,assign库还支持大部分Boost库容器,如array,circular_buffer,unordered等,用法同样与标准容器基本类似。
高级用法:
list_of()的嵌套使用
list_of()可以就地创建匿名列表,它可与嵌套在assign库用法中,创建复杂的数据结构
使用vector构造一个二维数组,使用list_of(list_of)的嵌套形式来初始化:
using namespace boost::assign;
vector<vector<int>> v = list_of(list_of(1)(2)) (list_of(3)(4));
v += list_of(5)(6), list_of(7)(8);
引用初始化列表:
在list_of之外assign库还有两个类似功能的ref_list_of()和cref_list_of(),这两个函数接受变量的引用作为参数来创建初始化匿名列表,较list_of()的效率更高,例如:
using namespace boost::assign;
int a = 1, b = 2, c = 3;
vector<int> v = ref_list_of<3>(a)(b)(c);
assert(v.size() == 3);
assign库还特别支持Boost中的指针容器,提供ptr_push_back(),ptr_list_of()等函数。