boost源码剖析----boost::any
boost源码剖析----boost::any
有的时候我们需要有一个万能类型来进行一些操作,这时候boost::any就派上用场了。
boost::Any testInt(10);
int val = static_cast<int>(testInt);
用法比较简单,我们来研究下boost::any是如何实现的。
原理
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);
我们需要我们的万能类型有如下的行为:
- 对外是一个一般的类,使用者压入参数的时候不应该关心类型
- 它只是一个中间层,具体保存数据的应该是一个模板类(Holder)
- 必须要能有方法支持任意类型的输入和输出为任意类型
实现
我们可以通过添加一个中间层来解决任何问题。
在boost::any中, 通过两个中间层来达成我们上面的目标, 类any作为对外的接口层,承担以模板作为参数并提供必要的对外方法。
类placeholder作为接口类,让any使用。而holder是一个模板类作为类placeholder的实现者, 这样就避免的any对泛型参数的要求(能自动推到导出来)。
我这里模仿了相关的实现,其代码结构应该是这样的:
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;
};
- type()提供了查询类型的能力
- 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);
总结
- 代码和boost::any中有一些出入,但是我们的目的是为了研究其实现,就忽略了某些细节
- 模板技巧: 模板类原来还可以这么用---声明非模板接口,并用模板类实现, 这样在使用这个接口的时候就能避免宿主类显示声明参数类型
- boost::any是整个boost库中最简单的类之一,但是某些代码细节还是非常值得学习和借鉴的。
- typeid和type_info 感觉有点像c++中的鸡肋,但是某些时候还是有用的
- 相关的代码上传到github上,有需要的同学可以看下any.h,
holder.h
boost源码剖析----boost::any的更多相关文章
- Boost源码剖析之:泛型指针类any
C++是强类型语言,所有强类型语言对型别的要求都是苛刻的,型别一有不合编译器就会抱怨说不能将某某型别转换为某某型别,当然如果在型别之间提供了转换操作符或是标准所允许的一定程度的隐式转换(如经过非exp ...
- STL源码剖析之组件
本篇文章开始,进行STL源码剖析的一些知识点,后续系列笔记全是参照<STL源码剖析>进行学习记录的 STL在现在的大部分项目中,实用性已经没有Boost库好了,毕竟STL中仅仅提供了一些容 ...
- jQuery之Deferred源码剖析
一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...
- Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现
声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析
项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...
- STL"源码"剖析-重点知识总结
STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
SpringMVC完成初始化流程之后,就进入Servlet标准生命周期的第二个阶段,即“service”阶段.在“service”阶段中,每一次Http请求到来,容器都会启动一个请求线程,通过serv ...
- 自己实现多线程的socket,socketserver源码剖析
1,IO多路复用 三种多路复用的机制:select.poll.epoll 用的多的两个:select和epoll 简单的说就是:1,select和poll所有平台都支持,epoll只有linux支持2 ...
随机推荐
- flex4+fms3.5+cs4开发实时音视频直播及点播详解
开发工具及环境: 1)flash builder4 2)flash cs4 3)flash media server3.5 fms部分 fms是adobe的流媒体服务器,不过是收费的,价格大概是ora ...
- GO语言练习:第二个工程--模拟音乐播放器
1.代码 2.编译及运行 1.目录结构 1.1) $ tree . ├── mplayer.go └── src ├── mlib │ ├── manager.go │ └── manager ...
- 使用plsql创建用户并授权(图形化界面)
使用sys用户登录数据库(或者有dba权限的[还不知道具体的区别,但是能用]) 在左边的对象列表中找到USERS,右键点击USERS,选择“新建用户”选项 其他安装下面的图片步骤来即可: OK!
- JAVA递归算法
1.什么是递归算法 递归算法就是直接或间接调用自己的算法 2.问题1:一列数的规则如下: 1.1.2.3.5.8.13.21.34 ,求第30位数是多少?使用递归实现 public class Fib ...
- 网络地址转换NAT原理及其作用
1 概述 1.1 简介 NAT英文全称是“Network Address Translation”,中文意思是“网络地址转换”,它是一个IETF(Internet Engineering Task F ...
- Runtime Error---Description: An application error occurred on the server....
[原]Runtime Error---Description: An application error occurred on the server.... 2010-1-7阅读2010 评论3 D ...
- HTML5初学总结
基本标签的使用 <!doctype html> <!--这是HTML5的申明,大小写都可以--> <html> <head> <title> ...
- jquery ajax传递多个对象或数组到后台
1.js对象创建:因为需要把对象json序列化后,才能传递到后台,后台根据json字符串进行反序列化. 2.Jquery $.ajax方法的配置 针对$.ajax方法的配置参数需要进行修改: 1) ...
- 了解C++默认编写并调用哪些函数
概念:编译器可以暗自为class创建default构造函数.copy构造函数.copy assignmengt构造函数,以及析构函数. 比如你写下:struct Node { }; 这就好像你写下这样 ...
- LNMP环境简易安装流程
1.关闭防火墙 [root@CentOS ~]# chkconfig iptables off 2.关闭selinux vi /etc/sysconfig/selinux //将SELINUX=enf ...