欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

boost库实用工具之assign

程序员文章站 2022-06-01 09:17:48
...

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