有的时候咱们须要有一个万能类型来进行一些操做,这时候boost::any就派上用场了。c++
boost::Any testInt(10); int val = static_cast<int>(testInt);
用法比较简单,咱们来研究下boost::any是如何实现的。git
c++是一个强类型的语言,要实现一个万能类型能够考虑用void*来保存数据,而后用类型转换进行操做,如:github
class MyAny{ MyAny(void* input):content_(input){ } template<typename T> T any_cast(){return *static_cast<T*>(content_)} private: void* content_; }
可是这样的写法有一个明显的缺点就是类型不安全。安全
显然咱们能够用template来改进咱们的程序:单元测试
template<typename T> class MyAny{ MyAny(T input):content_(input){ } T any_cast(){return content_;} private: T content_; }
可是这样咱们好像就没有解决问题:vector<MyAny
为了能写下以下的代码:测试
vector<MyAny> items; items.push_bacck(1); items.push_bacck(2.0);
咱们须要咱们的万能类型有以下的行为:this
咱们能够经过添加一个中间层来解决任何问题。
在boost::any中, 经过两个中间层来达成咱们上面的目标, 类any做为对外的接口层,承担以模板做为参数并提供必要的对外方法。
类placeholder做为接口类,让any使用。而holder是一个模板类做为类placeholder的实现者, 这样就避免的any对泛型参数的要求(能自动推到导出来)。
我这里模仿了相关的实现,其代码结构应该是这样的:code
class Any { public: Any() :holder_(nullptr){} template<typename ValueType> Any(const ValueType& val) : holder_(new Holder<ValueType>(val)){ } private: IHolder* holder_; }; mb_interface IHolder{ } template<typename ValueType> class Holder : public IHolder{ public: Holder(const ValueType& val) : value_(val){ } } public: ValueType value_; }
其中Holder提供了具体的数据存储服务,而 Any提供了对外的接口能力。
其中Holder必须提供两个方法:接口
mb_interface IHolder{ virtual ~IHolder(){} virtual const std::type_info& type() const = 0; virtual IHolder* clone() const = 0; };
在 Any中, 提供了如下几个个接口:
bool empty(){ return !holder_; } const std::type_info& type() const { return holder_ ? holder_->type() : typeid(void); } Any& operator=(Any rhs){ return swap(rhs); } template<typename ValueType> Any& operator=(const ValueType& val){ return Any(val).swap(*this); }
判断是否为空,查询类型操做,赋值操做
固然必须还有最重要的any_cast操做,咱们看其实现:
template<typename ValueType> ValueType* anyCast(Any* val){ return (val && val->type() == typeid(ValueType)) ? &static_cast<Holder<ValueType>*>(val->getHolder())->value_ : 0; } template<typename ValueType> ValueType anyCast(Any& val){ ValueType* rtn = anyCast<ValueType>(&val); if (!rtn)boost::throw_exception(badAnyCast()); return *rtn; }
果真好简单。呵呵~~~
最后添上单元测试,整个代码就完善了:
mb::Any testInt(10); mb::Any testDouble(10.0); mb::Any testInt2(testInt); EXPECT_EQ(testInt.empty(), false); EXPECT_EQ(std::string(testDouble.type().name()), "double"); EXPECT_EQ(std::string(testInt2.type().name()), "int"); int val = mb::anyCast<int>(testInt); EXPECT_EQ(val, 10);