boost 数据结构 boost::tuple boost::any boost::variant
Posted on 2016-05-24 11:15 bw_0927 阅读(320) 评论(0) 收藏 举报http://zh.highscore.de/cpp/boost/datastructures.html
http://www.cnblogs.com/my_life/articles/5502709.html
boost::any的实现原理:
http://blog.csdn.net/pongba/article/details/82811
在 Boost C++ 库中, 把一些类型定义为container显得不太合适, 所以就并没有放在 第 13 章 容器 里。 而把他们放在本章就比较合适了。 举例来说, boost::tuple 就扩展了 C++ 的数据类型 std::pair 用以储存多个而不只是两个值。
除了 boost::tuple, 这一章还涵盖了类 boost::any 和 boost::variant 以储存那些不确定类型的值。 其中 boost::any 类型的变量使用起来就像弱类型语言中的变量一样灵活。 另一方面, boost::variant 类型的变量可以储存一些预定义的数据类型, 就像我们用 union 时候一样。
boost::tuple 和 std::pair 之间最重要的一点不同点: 元组可以存储无限多个值!
就像 std::pair 有辅助函数 std::make_pair() 一样, 一个元组也可以用它的辅助函数 boost::make_tuple() 来创建。
元组也可以存储引用类型的值:
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <string>
#include <iostream>
int main()
{
std::string s = "Boris";
std::cout << boost::make_tuple(boost::ref(s), "Schaeling", 43) << std::endl;
}
像 C++ 这样的强类型语言要求给每个变量一个确定的类型。 而以 JavaScript 为代表的弱类型语言却不这样做, 弱类型的每个变量都可以存储数组、 布尔值、 或者是字符串。
库 Boost.Any 给我们提供了 boost::any 类, 让我们可以在 C++ 中像 JavaScript 一样的使用弱类型的变量。
#include <boost/any.hpp>
int main()
{
boost::any a = 1;
a = 3.14;
a = true;
}
需要注明的是: boost::any 并不能真的存储任意类型的值; Boost.Any 需要一些特定的前提条件才能工作。 任何想要存储在 boost::any 中的值,都必须是可拷贝构造的。
#include <boost/any.hpp>
#include <string>
int main()
{
boost::any a = 1;
a = 3.14;
a = true;
a = std::string("Hello, world!");
}
如果你企图把字符串 "Hello, world!" 直接赋给 a , 你的编译器就会报错, 因为由基类型 char 构成的字符串在 C++ 中并不是可拷贝构造的。
Boost.Variant 和 Boost.Any 之间的不同点在于 Boost.Any 可以被视为任意的类型, 而 Boost.Variant 只能被视为固定数量的类型,行为类似与union。
#include <boost/variant.hpp>
int main()
{
boost::variant<double, char> v;
v = 3.14;
v = 'A';
}
但是与 union 不同的是: boost::variant 可以储存像 std::string 这样的 class 类型的数据。 而union联合体中只能接受POD类型。
1 他与c语言中的union相对应
2 通过模板参数定义可以支持的类型
3 通过boost::get<T>()进行访问
4 可通过boost::static_visitor类与boost::apply_visitor(visitor, variant)函数.的组合来访问
#include <boost/variant.hpp>
#include <string>
#include <iostream>
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
std::cout << boost::get<double>(v) << std::endl;
v = 'A';
std::cout << boost::get<char>(v) << std::endl;
v = "Hello, world!";
std::cout << boost::get<std::string>(v) << std::endl;
}
想要分别处理各种不同类型的数据, Boost.Variant 为我们提供了一个名为 boost::apply_visitor() 的函数。
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <vector>
#include <string>
#include <iostream>
std::vector<boost::any> vector;
struct output :
public boost::static_visitor<>
{
void operator()(double &d) const
{
vector.push_back(d);
}
void operator()(char &c) const
{
vector.push_back(c);
}
void operator()(std::string &s) const
{
vector.push_back(s);
}
};
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
boost::apply_visitor(output(), v);
v = 'A';
boost::apply_visitor(output(), v);
v = "Hello, world!";
boost::apply_visitor(output(), v);
}
boost::apply_visitor() 第一个参数需要传入一个继承自 boost::static_visitor 类型的对象。
这个类必须要重载 operator()() 运算符来处理 boost::variant 每个可能的类型。
相应的, 例子中的 v 就重载了三次 operator() 来处理三种可能的类型:double, char 和 std::string。
再仔细看代码, 不难发现 boost::static_visitor 是一个模板。 那么,当 operator()() 有返回值的时候, 就必须返回一个模板才行。 如果 operator() 像例子那样没有返回值时, 你就不需要模板了。
boost::apply_visitor() 的第二个参数是一个 boost::variant 类型的值。
在使用时, boost::apply_visitor() 会自动调用跟第二个参数匹配的 operator()() 。
示例程序中的 boost::apply_visitor() 就自动调用了三个不同的 operator 第一个是 double 类型的, 第二个是 char 最后一个是 std::string。
boost::apply_visitor() 的优点不只是“自动调用匹配的函数”这一点。
更有用的是, boost::apply_visitor() 会确认是否 boost::variant 中的每个可能值都定义了相应的函数。
如果你忘记重载了任何一个函数, 代码都不会编译通过。
当然, 如果对每种类型的操作都是一样的, 你也可以像下面的示例一样使用一个模板来简化你的代码。
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <vector>
#include <string>
#include <iostream>
std::vector<boost::any> vector;
struct output :
public boost::static_visitor<>
{
template <typename T>
void operator()(T &t) const
{
vector.push_back(t);
}
};
int main()
{
boost::variant<double, char, std::string> v;
v = 3.14;
boost::apply_visitor(output(), v);
v = 'A';
boost::apply_visitor(output(), v);
v = "Hello, world!";
boost::apply_visitor(output(), v);
}
既然 boost::apply_visitor() 可以在编译期确定代码的正确性, 你就该更多的使用它而不是 boost::get()。
include/cetty/handler/codec/http/HttpPackage.h
template<typename T>
class ValueChecker : public boost::static_visitor<bool> {
public:
bool operator()(const T& value) const {
return true;
}
//任何非T的类型都返回false
template<typename U>
bool operator()(const U& value) const {
return false;
}
};
http://stackoverflow.com/questions/5312259/check-boostvariantt-for-null
boost::variant的两个函数
which() //使用的是第几个域
empty()
Boost.Variant has a never-empty guarantee, which means it must always store some value. It's empty member is guaranteed to always return false and exists only for compatibility.
You may want to check out Boost.Any instead.
不过你可以显示的把第一个域预留给null
#include <boost/variant.hpp>
#include <string>
#include <iostream>
using namespace std;
int main()
{
boost::variant<double, char, std::string> v;
std::cout << v.which() << endl;
std::cout << "empty: " << v.empty() << endl; //never empty
std::cout << std::endl;
v = 3.14;
std::cout << v << std::endl;
std::cout << "empty: " << v.empty() << endl;
std::cout << v.which() << endl;
std::cout << std::endl;
v = 'A';
std::cout << v << std::endl;
std::cout << "empty: " << v.empty() << endl;
std::cout << v.which() << endl;
std::cout << std::endl;
v = "Hello, world!";
std::cout << v << std::endl;
std::cout << "empty: " << v.empty() << endl;
std::cout << v.which() << endl;
}
输出:
0
empty: 0
3.14
empty: 0
0
A
empty: 0
1
Hello, world!
empty: 0
2
浙公网安备 33010602011771号