转:

原理

c++是一个强类型的语言,要实现一个万能类型可以考虑用void*来保存数据,然后用类型转换进行操作,如:

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

我们需要我们的万能类型有如下的行为:

  1. 对外是一个一般的类,使用者压入参数的时候不应该关心类型
  2. 它只是一个中间层,具体保存数据的应该是一个模板类(Holder)
  3. 必须要能有方法支持任意类型的输入和输出为任意类型

实现

我们可以通过添加一个中间层来解决任何问题。
在boost::any中, 通过两个中间层来达成我们上面的目标, 类any作为对外的接口层,承担以模板作为参数并提供必要的对外方法。
类placeholder作为接口类,让any使用。而holder是一个模板类作为类placeholder的实现者, 这样就避免的any对泛型参数的要求(能自动推到导出来)。

(为什么要让Holder继承IHolder,原因是为了让Any避开泛型)
我这里模仿了相关的实现,其代码结构应该是这样的:

class  Any
{
public:
Any() :holder_(nullptr){} template<typename ValueType>
Any(const ValueType& val)
: holder_(new Holder<ValueType>(val)){ }
private:
IHolder* holder_;
}; struct 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;
};
  1. type()提供了查询类型的能力
  2. clone()提供了产生数据的能力

在 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);

总结

    1. 代码和boost::any中有一些出入,但是我们的目的是为了研究其实现,就忽略了某些细节
    2. 模板技巧: 模板类原来还可以这么用---声明非模板接口,并用模板类实现, 这样在使用这个接口的时候就能避免宿主类显示声明参数类型
    3. boost::any是整个boost库中最简单的类之一,但是某些代码细节还是非常值得学习和借鉴的。
    4. typeid和type_info 感觉有点像c++中的鸡肋,但是某些时候还是有用的
    5. 相关的代码上传到github上,有需要的同学可以看下any.h,
      holder.h

Boost源码剖析之:泛型指针类any

boost any库的更多相关文章

  1. 如何在WINDOWS下编译BOOST C++库 .

    如何在WINDOWS下编译BOOST C++库 cheungmine 2008-6-25   写出来,怕自己以后忘记了,也为初学者参考.使用VC8.0和boost1.35.0.   1)下载boost ...

  2. Windows下如何使用BOOST C++库 .

    Windows下如何使用BOOST C++库 我采用的是VC8.0和boost_1_35_0.自己重新编译boost当然可以,但是我使用了 http://www.boostpro.com/produc ...

  3. Boost线程库学习笔记

    一.创建一个线程 创建线程 boost::thread myThread(threadFun); 需要注意的是:参数可以是函数对象或者函数指针.并且这个函数无参数,并返回void类型. 当一个thre ...

  4. Boost正则表达式库regex常用search和match示例 - 编程语言 - 开发者第2241727个问答

    Boost正则表达式库regex常用search和match示例 - 编程语言 - 开发者第2241727个问答 Boost正则表达式库regex常用search和match示例 发表回复   Boo ...

  5. Boost::thread库的使用

    阅读对象 本文假设读者有几下Skills [1]在C++中至少使用过一种多线程开发库,有Mutex和Lock的概念. [2]熟悉C++开发,在开发工具中,能够编译.设置boost::thread库. ...

  6. 一起学习Boost标准库--Boost.StringAlgorithms库

    概述 在未使用Boost库时,使用STL的std::string处理一些字符串时,总是不顺手,特别是当用了C#/Python等语言后trim/split总要封装一个方法来处理.如果没有形成自己的com ...

  7. 一起学习Boost标准库--Boost.texical_cast&format库

    今天接续介绍有关字符串表示相关的两个boost库: lexical_cast 将数值转换成字符串 format 字符串输出格式化 首先,介绍下lexical_cast ,闻其名,知其意.类似C中的at ...

  8. [boost] : test库

    最小化的测试套件minimal_test test库提供一个最小化的测试套件minimal_test, 类似lightweight_test适合入门级测试. 需要包含文件文#include <b ...

  9. Boost C++ 库 中文教程(全)

    Boost C++ 库 目录 第 1 章 简介 第 2 章 智能指针 第 3 章 函数对象 第 4 章 事件处理 第 5 章 字符串处理 第 6 章 多线程 第 7 章 异步输入输出 第 8 章 进程 ...

  10. UDF——处理二维网格的利器:Boost.Geometry库

    本文编译工具:VC++ UDF Studio 该插件可以直接在Visual Studio中一键编译.加载.调试UDF源码,极大提高编写排错效率,且支持C++,MFC,Windows API和第三方库, ...

随机推荐

  1. 有史来最大改变 Android 5.0十大新特性

    有史来最大改变 Android 5.0十大新特性 2014.10.16 14:51:31 来源:腾讯数码作者:腾讯数码 ( 0 条评论 )   距离Android系统上一次重大更新不到一年的时间,谷歌 ...

  2. 理解callback function in javascript

    以下内容主要摘自[1,2] (1)In javascript, functions are first-class objects, which means functions can be used ...

  3. 疯狂房价"逼死"年轻人,别指望中国未来能出人才了

    社会高房价,杀死那个学者 --北京青年学者生存侧记 这一轮,房价又上涨了,只有更疯狂. 几年前,北京三环内的房价突破5万,世人惊呼:没几年,四环5万了,五环5万了:这一轮,北京城乡结合部,哪怕脏乱差之 ...

  4. 通过TStringList保存csv文件,只要循环.Add表格里面的每行记录进去,保存即可

    dlgSave := TSaveDialog.Create(nil); dlgSave.filter := 'CSV文件|*.CSV'; dlgSave.DefaultExt := '*.CSV'; ...

  5. Activiti工作流学习(三)Activiti工作流与spring集成

    一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用sprin ...

  6. Android 进程常驻(使用第三方MarsDaemon)(虽然不可用,但是还是保留下。)

    github地址: https://github.com/Marswin/MarsDaemon 原理分析: Android 进程常驻(0)----MarsDaemon使用说明 Android 进程常驻 ...

  7. js 无缝滚动效果学习

    <!DOCTYPE html> <html> <head> <title>无缝滚动测试</title> <meta http-equi ...

  8. tachyon of zybo cluster

    把Tachyon层加入spark和hadoop之间,以加速集群 官网:http://tachyon-project.org/ github:https://github.com/amplab/tach ...

  9. 优惠分摊算法 php版

    <?php /* * 优惠分摊,算法很多,这里是从shopnc挖出来,适合优惠条件过滤的算法,实质很简单,但是理解难度还是有一点 * * 一个订单的商品,如果不参与某种活动,需要分摊优惠,一般来 ...

  10. JQ第三天//基本纯代码

    一.让图片飞 代码:<script type="text/javascript">        $(function () {            $(docume ...