assign
- 许多时候我们需要为容器初始化或者赋值,填入大量的数据时,用标准库中的容器填充步骤非常的麻烦,必须重复的使用insert或者push_back之类的成员函数。于是在boost中出现了assign.
- assign库重载了赋值操作符operator += ,逗号操作符operator,和括号操作符 operator(), 我们可以用很简单的方法非常方便的对标准容器赋值或者初始化。在需要填充大量初始化值的时候非常方便。C++11标准也提供了类似的初始化工作,但是功能却没有assign库那么完备。
- 使用assign库应包含头文件assign.hpp头文件
#include <boost\assign.hpp>
using namespace boost;
assign中的工具类
list_inserter
- list_inserter是assign库中用来操作容器的工具类,它类似于std::back_inserter,但增加了很多操作符重载和助手类来简化代码。
- 该工具类内部存储了一个函数对象insert_用来操作容器,这个函数对象包装了容器的push_back和push_front等操作。
- list_inserter成员函数的另一个特点是返回*this指针,这使得它可以像标准流操作一样串联操作,达到简化代码的目的
list_inserter& operator,(const T& r) /// 重载 operator ,
{
insert_(r); /// 像容器添加元素
return *this; /// 返回自身的引用
}
operator+=
由于list_inserter重载了操作符+=和逗号,我们就可以让代码变得简洁
使用assign库时必须使用using指示符,这有这样才能让重载的+=,等操作符在作用域内生效
例如:
void assign_case1()
{
using namespace boost::assign;
std::vector<int> v;
v += 1, 2, 3, 4, 5, 6 * 6;
for (auto & x : v)
cout << x << " ";
cout << endl;
std::set<string> s;
s += "cpp", "java", "c#", "python";
for (auto &x : s)
cout << x << " ";
cout << endl;
std::map<int, string> m;
m += make_pair(1, "one"), make_pair(2, "two");
}
operator ()
- operator += 只作用于容器,而且在处理map容器时就显得有些麻烦了,所以我们可以直接使用工厂函数 insert()/push_front()/push_back(),直接利用他们返回的list_inserter对象来填入数据。例如:
#include <forward_list>
void assign_case2()
{
using namespace boost::assign;
vector<int> v;
push_back(v)(1)(2)(3)(4)(5); /// 使用工厂函数
list<string> l;
push_front(l)("cpp")("java")("C#")("python");
forward_list<string> f1; /// C++11中向前的单向链表
push_front(l)("matrix")("reload");
set<double> s;
insert(s)(3.14)(0.983)(1.175);
map<int, string> m;
insert(m)(1, "one")(2, "two");
}
generic_list
- list_inserter解决的对容器的赋值问题,但有时候我们需要在容器构造的时候就完成数据的填充,这用方式赋值就比较高效。
c++11标准库中引用了初始化列表std::initializer_list,而boost.assign库则提供了功能类似的generic_list, - generic_list与list_inserter类似,也重载了逗号和括号操作符,因为要在初始化时与容器互操作,它还额外增加了一些容器操作函数。
- generic_list内部使用了std::deque存储元素,大多数操作都转换为deque的push_back()例如:
generic_list& operator ,(const T& u)
{
this->push_back(u);
return *this;
}
一个小的例子:
/ generic_list 构造的时候完成数据的填充
void assign_case3()
{
using namespace boost::assign;
vector<int> v;
push_back(v), 1, 2, 3, 4, 5;
push_back(v)(6), 7, 64 / 8, (9), 10;
for (auto& x : v)
cout << x << ",";
cout << endl;
deque<string> d;
push_front(d)() = "cpp", "java", "c#", "python";
assert(d.size() == 5);
for (auto& x : d)
cout << x << ",";
cout << endl;
}
初始化容器
assign 库提供的三个工厂函数 list_of , map_list_of/pair_list_of和tuple_list_of 它们能够产生generic_list 对象,然后我们就可以像list_inserter一样使用operator()和operator ,来填充数据。
因为 generic_list 提供到容器类型的隐式转型操作,所以他可以赋值给任意容器,当然我们也可以显示调用显示转换函数
// 初始化列表
/// 3个工厂函数 list_of, map_list_of/pair_list_of和tuple_list_of.
void assign_case4()
{
using namespace boost::assign;
vector<int> v = list_of(1)(2)(3)(4)(5);
// v = [1,2,3,4,5]
deque<string> d = (list_of("power")("bomb"), "phazon", "suit");
// d = [power bomb phazon suit]
set<int> s = (list_of(10), 20, 30, 40, 50);
// s = {10 20 30 40 50}
map<int, string> m = list_of(make_pair(1, "one"))(make_pair(2, "two"));
// m = [(1, “one”) (2, “two”)]
map<int, int> m1 = map_list_of(1, 2)(3, 4)(5, 6);
//m1 = [(1, 2)(3, 4)(5, 6)]
map<int,string> m2= map_list_of(1, "one")(2, "two");
//m2 = [(1, "one")(2, "two")]
}
减少重复输入
在填充数据时会遇到重复数据输入的问题,如果用之前的方法就要写较多的代码,我们可以用list_inserter 和 generic_list 都提供了成员函数repeat(), repeat_fun() 和 range()来进去工作量。这三个函数简要申明如下:
list& repeat(std::size_t sz, U u);
list& repeat_fu(std::size_t sz, Nullary_function fun);
list& range(SinglePassIterator first, SinglePassIterator last);
简单的例子使用:
#include <cstdlib>
/// 减少重复输入
void assign_case5()
{
using namespace boost::assign;
vector<int> v = list_of(1).repeat(3, 2)(3)(4)(5);
//v = 1,2,2,2,3,4,5
for (auto& x : v)
cout << x << ",";
cout << endl;
multiset<int> ms;
insert(ms).repeat_fun(5, &rand).repeat(2, 1), 10;
//ms = x,x,x,x,x,1,1,10
for (auto& x : ms)
cout << x << ",";
cout << endl;
deque<int> d;
push_front(d).range(v.begin(), v.begin() + 5);
//d = 3,2,2,2,1
for (auto& x : d)
cout << x << ",";
cout << endl;
}
操作非标准容器
assign 库不仅支持全部8 个标准容器(vector, string, deque, list, set, multiset, map, multimap),也对容器适配器提供了适当的支持,包括stack, queue, priority_queue
#include <stack>
#include <queue>
void assign_case6()
{
using namespace boost::assign;
stack<int> stk = (list_of(1), 2, 3).to_adapter();
stk += 4, 5, 6;
for (; !stk.empty();)
{
cout << stk.top() << " ";
stk.pop();
}
cout << endl;
queue<string> q = (list_of("china")("us")("uk")).
repeat(2, "russia").to_adapter();
push(q)("germany");
for (; !q.empty();)
{
cout << q.front() << " ";
q.pop();
}
cout << endl;
priority_queue<double> pq = (list_of(1.414), 1.732, 2.236).to_adapter();
push(pq), 3.414, 2.71828;
for (; !pq.empty();)
{
cout << pq.top() << " ";
pq.pop();
}
}