c++11 boost - 容器(4) any、variant、multi_array、property_tree

2018-07-12 15:37:58

any 容器只能存放一个元素,该元素可以是任意类型。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

#include <boost/exception/all.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/assign.hpp>
#include <boost/any.hpp>
using namespace boost;

//////////////////////////////////////////
void case1()
{
    any a(10);

    int n = any_cast<int>(a);
    assert(n == 10);

    any_cast<int&>(a) = 20;
    assert(any_cast<int>(a) == 20);;

    try
    {
        any a;   //空any对象,不持有任何类型
        any_cast<int>(a); //报错
    }
    catch(boost::exception&)
    {   
        //cout << current_exception_diagnostic_information();
    }

    any a1, a2(2.0);
    assert(any_cast<int*>(&a1) == nullptr);
    assert(any_cast<string*>(&a2) == nullptr);

}

void case2()
{
    any a(100);
    a = string("char*");
    a = vector<vector<int> >();

    a = "c str";
    cout << a.type().name() << endl;
    cout << any_cast<const char*>(&a) << endl;
    cout << any_cast<const char*>(a) << endl;

    string *ps = new string("abc");     //不好的使用方式
    a = ps;
    if (!a.empty() && any_cast<string*>(a))
    {       cout << *any_cast<string*>(a)<< endl;   }

}

//保存指针,使用shared_ptr
template<typename T>
bool can_cast(any &a)
{   return typeid(T) == a.type();}

template<typename T>
T& get(any &a)
{
    assert(can_cast<T>(a));
    return *any_cast<T>(&a);
}

template<typename T>
T* get_pointer(any &a)
{
    assert(can_cast<T>(a));
    return any_cast<T>(&a);
}

template<typename T>
any make_ptr_any(T *p = 0)
{   return any(boost::shared_ptr<T>(p));}

template<typename T>
boost::shared_ptr<T>& get_shared(any &a)
{
    assert(can_cast<boost::shared_ptr<T> >(a));
    return *any_cast<boost::shared_ptr<T> >(&a);
}

void case3()
{
    any a;
    int x = 1;
    a = x;
    assert(can_cast<int>(a));
    get<int>(a) = 10;
    *get_pointer<int>(a) = 20;

    a = make_ptr_any<string>(new string("long"));
    cout << *get_shared<string>(a) << endl;
    a = make_ptr_any<vector<int> >(new vector<int>);

}

//输出功能
template<typename T > struct any_print
{
    void operator()(any &a)
    try
    {
        cout << *any_cast<T>(&a) << endl;   
    }
    catch(bad_any_cast &)
    {
        cout << "print error" << endl;
    }

};

template<typename T >
struct any_print<boost::shared_ptr<T> >
{
    void operator()(any &a)
    try
    {
        cout << **any_cast<boost::shared_ptr<T> >(&a) << endl; 
    }
    catch(bad_any_cast &)
    {
        cout << "print error" << endl;
    }
};

void case4()
{
    any a;

    a = 10;
    any_print<int>()(a);

    auto ps = boost::make_shared<string>("metroid");
    a = ps;
    any_print< boost::shared_ptr<string> >()(a);

}

void case5()
{
    vector<any> v;
    v.push_back(10);                                    //int
    v.push_back(1.414);                                 //double
    v.push_back(boost::shared_ptr<int>(new int(100) ));    //shared_ptr

    using namespace boost::assign;
    vector<any> v2 = list_of<any>(10)(0.618)(string("char"));
    cout << v2.size();

}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
}
[root@192 c++]# g++ -std=c++11 main.cpp 
[root@192 c++]# ./a.out 
PKc
0x247f0f8
c str
abc
long
10
metroid
3


variant 是一种可变类型,是对 union 概念的增强,可以持有string、vector等负载类型,默认的类型数量为20个。已被c++17收录。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

#include <boost/assign.hpp>
#include <boost/variant.hpp>
using namespace boost;

void case1()
{
    variant<int, float, string> v;
    v = "123";

    cout << v << endl;
}

void case2()
{
    typedef variant<int, double, string> var_t;

    var_t v(1);                                 //v->int
    v = 2.13;                                       //v->double
    assert(v.type() == typeid(double));
	
	//get访问
    var_t v2("string type");                        //v2->string
    cout << get<string>(v2);

    v2 = v;                                         //v2->double

    cout << get<int>(var_t(108));

}

void case3()
{
    typedef variant<int, double, string> var_t;
    var_t v;
    assert(v.type() == typeid(int));
    assert(v.which() == 0);  //索引位置为0

    v = "variant demo";
    cout << *get<string>(&v) << endl;

    try
    {
        cout << get<double>(v) << endl;
    }
    catch (bad_get &)
    {
        cout << "bad_get" << endl;
    }
}

struct var_print : public static_visitor<>
{
    template<typename T>
    void operator()(T &i) const
    {
        i *= 2;
        cout << i << endl;
    }

    void operator()(vector<int> &v) const
    {
        v.reserve(v.size()*2);
        copy(v.begin(),v.end(),back_inserter(v)) ;
        for (auto& x : v)
        {
            cout << x << ",";                       //输出以验证
        }
        cout << endl;
    }

};

//访问器
void case4()
{
    typedef variant<int, double, vector<int> > var_t;

    var_t v(1);
    var_print vp;

    apply_visitor(vp, v);
    v = 3.414;
    apply_visitor(vp, v);

    //using namespace boost::assign;
    //v = vector<int>({1,2});
    vector<int> tmp = {1,2};
    v = tmp;
    apply_visitor(vp, v);

    auto vp2 = apply_visitor(vp);
    vp2(v);

}

//模板元编程mpl,突破限制20
template<BOOST_VARIANT_ENUM_PARAMS(typename T)>
void op_var(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& v)
{   cout << v << endl;}

#include <boost/mpl/vector.hpp>
void case5()
{
    typedef boost::mpl::vector<
        int, double, std::vector<string> > var_types;

    make_variant_over<var_types>::type v;
    v = 2.13;

}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
}
[root@192 c++]# g++ -std=c++11 main.cpp 
[root@192 c++]# ./a.out 
123
string type108variant demo
bad_get
2
6.828
1,2,1,2,
1,2,1,2,1,2,1,2,


multi_array 多维数组。

// Copyright (c) 2015
// Author: Chrono Law
#include <iostream>
using namespace std;

#include <boost/assign.hpp>
#include <boost/multi_array.hpp>
using namespace boost;

void case1()
{
    multi_array<int, 3> ma(extents[2][3][4]);   //ma[0-1][0-2][0-3]

    auto shape = ma.shape();
    //返回规格
    for (size_t i = 0; i < ma.num_dimensions(); ++i)
    {
        cout << shape[i] << ",";
    }
    cout << endl << ma.num_elements() << endl;

    for (int i = 0,  v = 0; i < 2; ++i)
        for (int j = 0; j < 3;++j)
            for (int k = 0;k < 4;++k)
            {
                ma[i][j][k] = v++;
            }

    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 3;++j)
        {
            for (int k = 0;k < 4;++k)
            {
                cout << ma[i][j][k] << ",";
            }
            cout << endl;
        }
        cout << endl;
    }

    //cout << ma[2][3][4];

	//ma[0][1][2]
    std::array<size_t, 3> idx = {0,1,2};
    ma(idx) = 10;
    cout << ma(idx) << endl;
}

//修改形状和大小
void case2()
{
    multi_array<int, 3> ma(extents[2][3][4]);
    assert(ma.shape()[0] == 2);

    std::array<std::size_t, 3> arr = {4,3,2};
    ma.reshape(arr);
    assert(ma.shape()[0] == 4);

    ma.resize(extents[2][9][9]);
    assert(ma.num_elements() == 2*9*9);
    assert(ma.shape()[1] == 9);
}

//子视图,查看其中的一部分
void case3()
{
    typedef multi_array<int, 2> ma_type;
    multi_array<int, 2> ma(extents[3][4]) ;

    typedef ma_type::index_range range;
    //indices[range(0,2)][range(0,2)];

    auto view = ma[indices[range(0,2)][range(0,2)] ];

    cout << view.num_elements() << endl;
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 2;++j)
        {
            cout << view[i][j] << ",";
        }
        cout << endl;
    }
    cout << *view.shape() << endl;

}

//利用普通数组的内存,适配成多维数组
//也就是多维数组用的是普通数组的内存
void case4()
{
    int arr[12];
    for (int i = 0;i < 12;++i)
    {   arr[i] = i; }

	//这里的二维数组总共为3*4个元素,内存使用的是int arr[12]
    multi_array_ref<int, 2> mar(arr, extents[3][4]);

    for (size_t i = 0; i < 3; ++i)
    {
        cout << "(";
        for(size_t j = 0;j < 4;++j)
        {
            cout << mar[i][j]++;
            cout << (j!=3?',':' ');
        }
        cout << ")" << endl;
    }

    const_multi_array_ref<int, 2> cmar(arr, extents[2][6]);

    for (size_t i = 0; i < 2; ++i)
    {
        cout << "(";
        for(size_t j = 0;j < 6;++j)
        {
            cout << cmar[i][j];
            cout << (j!=5?',':' ');
        }
        cout << ")" << endl;
    }

}

void case5()
{
    //multi_array<int, 3> ma(vector<int>(assign::list_of(2)(2)));
    multi_array<int, 3> ma(vector<int>{2,2,2});
    auto shape = ma.shape();
    for (size_t i = 0; i < ma.num_dimensions(); ++i)
    {
        cout << shape[i] << ",";
    }

}

//设置索引计数,默认从0开始
void case6()
{
    typedef multi_array<int, 3> ma_type;
    typedef ma_type::extent_range range;
    ma_type ma(extents [range(1,5)][4][range(-2,2)]); //ma[1-4][0-3][-2 到 -1]
    ma[1][0][-2] = 10;

    ma.reindex(1);
    assert(ma[1][1][1] == 10);
    ma.reindex(std::array<int,3>{1,0,-4});
    assert(ma[1][0][-4] == 10);

    cout << *ma.index_bases() << endl;
}

//更灵活的生成子视图
void case7()
{
    using namespace boost::detail::multi_array;

    typedef multi_array<int, 3> ma_type;
    typedef ma_type::index_range range;
    ma_type ma(extents[9][8][7]);

	//前3列,2-5列,全部
    auto view = ma[indices[range()< 3L][2L<=range()<= 5L][range()] ];
    cout << *view.shape() << endl;

}

int main()
{
    case1();
    case2();
    case3();
    case4();
    case5();
    case6();
    case7();
}
[root@192 c++]# ./a.out 
2,3,4,
24
0,1,2,3,
4,5,6,7,
8,9,10,11,

12,13,14,15,
16,17,18,19,
20,21,22,23,

10
4
0,0,
0,0,
2
(0,1,2,3 )
(4,5,6,7 )
(8,9,10,11 )
(1,2,3,4,5,6 )
(7,8,9,10,11,12 )
2,2,2,1
3


 备注

1.编译器版本gcc4.8.5,运行环境centos7 64位
2.本文只做简单记录用,详细用法请参考 Boost Library,或者是罗剑锋的 boost程序库完全开发指南 书本
3..原文地址http://www.freecls.com/a/2712/a8


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。