boost::any 类型 实现原理

dacxu 2014-03-23 03:38:14
本人在研究boost::any类型的原理,主要参考Kevlin Henney的一篇名为valued conversions的论文。
下面是代码:

#include <iostream>
#include <string>

class any
{
public:
//Representation and basic construction of a generalized union type.
any(): content(0)
{
}

~any()
{
delete content;
}

const std::type_info &type_info() const
{
return content ? content->type_info() : typeid(void);
}

//INWARD CONVERSIONS
any(const any &other) : content(other.content ? other.content->clone() : 0)
{
}

template<typename value_type>
any(const value_type &value) : content(new holder<value_type>(value))
{
}

any &swap(any &rhs)
{
std::swap(content, rhs.content);
return *this;
}

any &operator=(const any &rhs)
{
return swap(any(rhs));
}

template<typename value_type>
any &operator=(const value_type &rhs)
{
return swap(any(rhs));
}

//OUTWARD CONVERSIONS
operator const void *() const
{
return content;
}

template<typename value_type>
bool copy_to(value_type &value) const
{
const value_type *copyable = to_ptr<value_type>();
if(copyable)
value = *copyable;
return copyable;
}

template<typename value_type>
const value_type *to_ptr() const
{
return type_info() == typeid(value_type)?
&static_cast<holder<value_type> *>(content)->held : 0;
}

private:
class placeholder
{
public:
virtual ~placeholder()
{
}
virtual const std::type_info & type_info() const = 0;
virtual placeholder *clone() const = 0;
};

template<typename value_type>
class holder : public placeholder
{
public:
holder(const value_type &value) : held(value)
{
}

virtual const std::type_info &type_info() const
{
return typeid(value_type);
}

virtual placeholder *clone() const
{
return new holder(held);
}

const value_type held;
};

placeholder *content;
};

template<typename value_type>
value_type any_cast(const any &operand)
{
const value_type *result = operand.to_ptr<value_type>();

//return result ? *result : throw std::bad_cast();
if (result)
return *result;
throw std::bad_cast();
}

int main(int argc, char* argv[])
{
any i_a = 3;
int i_b = any_cast<int>(i_a);
std::cout<<i_a<<"\t"<<i_b<<std::endl;

any s_a = std::string("demo");
std::string s_b = any_cast<std::string>(s_a);
std::cout<<s_a<<"\t"<<s_b<<std::endl;

return 0;
}

具体问题如下:
any_cast函数,如果我采用书中的代码return result ? *result : throw std::bad_cast();会异常,
但如果 采用我的
if (result)
return *result;
throw std::bad_cast();
可以正确运行。但是,这两段代码意义是一样的,是否有大神能帮助分析一下?
编译环境是VS2008, 谢谢
...全文
168 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
dacxu 2014-03-25
  • 打赏
  • 举报
回复
引用 2 楼 unituniverse2 的回复:
[quote=引用 楼主 u012702526 的回复:] 本人在研究boost::any类型的原理,主要参考Kevlin Henney的一篇名为valued conversions的论文。 下面是代码:

#include <iostream>
#include <string>

class any
{
public:
	//Representation and basic construction of a generalized union type.
	any(): content(0)
	{
	}

	~any()
	{
		delete content;
	}
	
	const std::type_info &type_info() const
	{
		return content ? content->type_info() : typeid(void);
	}

	//INWARD CONVERSIONS 
	any(const any &other) : content(other.content ? other.content->clone() : 0)
	{
	}

	template<typename value_type>
	any(const value_type &value) : content(new holder<value_type>(value))
	{
	}
	
	any &swap(any &rhs)
	{
		std::swap(content, rhs.content);
		return *this;
	}

	any &operator=(const any &rhs)
	{
		return swap(any(rhs));
	}

	template<typename value_type>
	any &operator=(const value_type &rhs)
	{
		return swap(any(rhs));
	}
	
	//OUTWARD CONVERSIONS
	operator const void *() const
	{
		return content;
	}

	template<typename value_type>
	bool copy_to(value_type &value) const
	{
		const value_type *copyable = to_ptr<value_type>();
		if(copyable)
			value = *copyable;
		return copyable;
	}

	template<typename value_type>
	const value_type *to_ptr() const
	{
		return type_info() == typeid(value_type)? 
			&static_cast<holder<value_type> *>(content)->held : 0;
	}

private:
	class placeholder
	{
	public:
		virtual ~placeholder()
		{
		}
		virtual const std::type_info & type_info() const = 0;
		virtual placeholder *clone() const = 0;
	};

	template<typename value_type>
	class holder : public placeholder
	{
	public:
		holder(const value_type &value)	: held(value)
		{
		}

		virtual const std::type_info &type_info() const
		{
			return typeid(value_type);
		}

		virtual placeholder *clone() const
		{
			return new holder(held);
		}

		const value_type held;
	};

	placeholder *content;
};

template<typename value_type>
value_type any_cast(const any &operand)
{
	const value_type *result = operand.to_ptr<value_type>();
	
	//return result ? *result : throw std::bad_cast();
	if (result)
		return *result;
	throw std::bad_cast();
}

int main(int argc, char* argv[])
{
	any i_a = 3;
	int i_b = any_cast<int>(i_a);	
	std::cout<<i_a<<"\t"<<i_b<<std::endl;
	
	any s_a = std::string("demo");
	std::string s_b = any_cast<std::string>(s_a);
	std::cout<<s_a<<"\t"<<s_b<<std::endl;

	return 0;
}
具体问题如下: any_cast函数,如果我采用书中的代码return result ? *result : throw std::bad_cast();会异常, 但如果 采用我的 if (result) return *result; throw std::bad_cast(); 可以正确运行。但是,这两段代码意义是一样的,是否有大神能帮助分析一下? 编译环境是VS2008, 谢谢
我个人不是很喜欢这个any。原因是再小的类型都会被强制分配在堆里面。。。   实现原理上:首先把静态类型转换成运行时类型。holder就是干这个的。至于为什么可行。。。因为再”动态“的类型在整个C++程序中都是需要提前定义好的才能用来实例化,而不可能真的到了编译时根据外部输入临时生成。这会让你想到什么呢?? ——显然所有的可实例化类型仍然是编译时已知的。   你后面问的问题是这样的:因为?:是运算符。到目前为止除了逗号运算符外所有的运算符都是不考虑边界效应的。就比如经常有人在csdn问的那个未定义行为(i++)+(i++)的结果是什么那样。既然是运算符,x=a?b:c的实际步骤不等同于if(a)x=b;else x=c;而是先生成a、b、c然后再去根据a的值选择b还是c赋值给x。换句话说不论a最终为多少,b和c都是要做实际操作的。我记得之前微软的编译器自己做了扩展说如果a是指针则在空指针的情况下在?:里面为假的情况不去取内容,用来兼容那些非规范的代码。但是这种扩展仍然是没有保证的。标准对这类情况的规定是未定义的结果。 而if语句肯定不存在什么边界效应(线程内环境下)。如果有了那就是编译器的不良设计问题[/quote] 可是在any_cast函数中,result实际上不是空指针啊
dacxu 2014-03-25
  • 打赏
  • 举报
回复
引用 1 楼 taodm 的回复:
别浪费时间在研究高阶模板的实现上。能正确用好any就很好了。 人家可能用C++11标准的编译器的。
这个any的实现 不需要C++ 11的支持, 使用的技术 只包括 C++原生支持的 继承,多态和 函数模板,类模板。如果 你有时间,可以帮我分析 一下,问题比较怪异
unituniverse2 2014-03-25
  • 打赏
  • 举报
回复
引用 4 楼 u012702526 的回复:
可是在any_cast函数中,result实际上不是空指针啊
对了我再强调一下,就像你引用我的那个回答里的时候那样 result ? *result : throw std::bad_cast(); 这个是先执行 result、*result、throw std::bad_cast() 再把这3者做为输入来通过“?:”输出到return。可是当throw std::bad_cast()的时候就已经异常了所以根本执行不到return了,就算是result为真也不行。而if(result) return(*result) else throw std::bad_cast();中只要一开始if那里为真就根本碰不到else后面的throw那里去。
unituniverse2 2014-03-25
  • 打赏
  • 举报
回复
引用 4 楼 u012702526 的回复:
可是在any_cast函数中,result实际上不是空指针啊
不用纠结这些了。你知道?:是运算符就可以了。运算符是不能替代if else的,存在副作用(side-effect)。当务之急是消除代码的未定义行为。
unituniverse2 2014-03-23
  • 打赏
  • 举报
回复
引用 楼主 u012702526 的回复:
本人在研究boost::any类型的原理,主要参考Kevlin Henney的一篇名为valued conversions的论文。 下面是代码:

#include <iostream>
#include <string>

class any
{
public:
	//Representation and basic construction of a generalized union type.
	any(): content(0)
	{
	}

	~any()
	{
		delete content;
	}
	
	const std::type_info &type_info() const
	{
		return content ? content->type_info() : typeid(void);
	}

	//INWARD CONVERSIONS 
	any(const any &other) : content(other.content ? other.content->clone() : 0)
	{
	}

	template<typename value_type>
	any(const value_type &value) : content(new holder<value_type>(value))
	{
	}
	
	any &swap(any &rhs)
	{
		std::swap(content, rhs.content);
		return *this;
	}

	any &operator=(const any &rhs)
	{
		return swap(any(rhs));
	}

	template<typename value_type>
	any &operator=(const value_type &rhs)
	{
		return swap(any(rhs));
	}
	
	//OUTWARD CONVERSIONS
	operator const void *() const
	{
		return content;
	}

	template<typename value_type>
	bool copy_to(value_type &value) const
	{
		const value_type *copyable = to_ptr<value_type>();
		if(copyable)
			value = *copyable;
		return copyable;
	}

	template<typename value_type>
	const value_type *to_ptr() const
	{
		return type_info() == typeid(value_type)? 
			&static_cast<holder<value_type> *>(content)->held : 0;
	}

private:
	class placeholder
	{
	public:
		virtual ~placeholder()
		{
		}
		virtual const std::type_info & type_info() const = 0;
		virtual placeholder *clone() const = 0;
	};

	template<typename value_type>
	class holder : public placeholder
	{
	public:
		holder(const value_type &value)	: held(value)
		{
		}

		virtual const std::type_info &type_info() const
		{
			return typeid(value_type);
		}

		virtual placeholder *clone() const
		{
			return new holder(held);
		}

		const value_type held;
	};

	placeholder *content;
};

template<typename value_type>
value_type any_cast(const any &operand)
{
	const value_type *result = operand.to_ptr<value_type>();
	
	//return result ? *result : throw std::bad_cast();
	if (result)
		return *result;
	throw std::bad_cast();
}

int main(int argc, char* argv[])
{
	any i_a = 3;
	int i_b = any_cast<int>(i_a);	
	std::cout<<i_a<<"\t"<<i_b<<std::endl;
	
	any s_a = std::string("demo");
	std::string s_b = any_cast<std::string>(s_a);
	std::cout<<s_a<<"\t"<<s_b<<std::endl;

	return 0;
}
具体问题如下: any_cast函数,如果我采用书中的代码return result ? *result : throw std::bad_cast();会异常, 但如果 采用我的 if (result) return *result; throw std::bad_cast(); 可以正确运行。但是,这两段代码意义是一样的,是否有大神能帮助分析一下? 编译环境是VS2008, 谢谢
我个人不是很喜欢这个any。原因是再小的类型都会被强制分配在堆里面。。。   实现原理上:首先把静态类型转换成运行时类型。holder就是干这个的。至于为什么可行。。。因为再”动态“的类型在整个C++程序中都是需要提前定义好的才能用来实例化,而不可能真的到了编译时根据外部输入临时生成。这会让你想到什么呢?? ——显然所有的可实例化类型仍然是编译时已知的。   你后面问的问题是这样的:因为?:是运算符。到目前为止除了逗号运算符外所有的运算符都是不考虑边界效应的。就比如经常有人在csdn问的那个未定义行为(i++)+(i++)的结果是什么那样。既然是运算符,x=a?b:c的实际步骤不等同于if(a)x=b;else x=c;而是先生成a、b、c然后再去根据a的值选择b还是c赋值给x。换句话说不论a最终为多少,b和c都是要做实际操作的。我记得之前微软的编译器自己做了扩展说如果a是指针则在空指针的情况下在?:里面为假的情况不去取内容,用来兼容那些非规范的代码。但是这种扩展仍然是没有保证的。标准对这类情况的规定是未定义的结果。 而if语句肯定不存在什么边界效应(线程内环境下)。如果有了那就是编译器的不良设计问题
taodm 2014-03-23
  • 打赏
  • 举报
回复
别浪费时间在研究高阶模板的实现上。能正确用好any就很好了。 人家可能用C++11标准的编译器的。
这个包主要实现了最简单的Lex和Yacc环境,包含了最少的但是必须的文件。
同时还包含了一个MinGW的GNU的C++编译器环境:)可以直接使用:)

这个包包含的文件列表:

MinGW GNU的C/C++编译程序(windows版本)
bison.exe GNU的yacc程序
bison.hairy GNU的yacc程序运行需要的文件
bison.simple GNU的yacc程序运行需要的文件
flex.exe GNU的lex程序
ini.bat 这个lex和yacc环境的环境变量配置
lexyacc.bat 这个lex和yacc环境的启动程序
Readme.txt 本说明文件

使用方法:

1. 鼠标双击lexyacc.bat文件运行
2. 在弹出的DOS命令行中利用CD切换到你的lex和yacc源文件所在的目录(calc)
3. 对lex源文件执行flex calc.l
4. 对yacc源文件执行bison -d calc.y

经过上面的四个步骤就生成了你需要的C/C++源文件,剩下的事情就是编译
这里生成的C/C++源程序了。

5. g++ lex.yy.c calc.tab.c -o calc

最后谢谢您的使用,也希望您提出宝贵的意见或者建议,我会认真考虑您的
意见或者建议的。可以发邮件到pandaxcl@163.com和我联系。

博客:http://blog.csdn.net/pandaxcl
论坛:http://www.autodev.net


大家好,本人历时两年构思了四年,目前完成了一半的自动化C++程序设计代码库
(autocxx)总算可以拿出来见人了,大家多到论坛(http: //www.autodev.net)
或者博客(http://blog.csdn.net/pandaxcl)提些意见吧:)代码是开源的;)
下面是整个项目的文档目录:

* 自动化C++程序设计
* 基础篇
* C++里的模板语言
* 静态诊断
* 为什么说模版是C++的子语言
* 静态数学运算
* 静态选择结构
* 静态循环结构
* 运算结果的保存
* 基本类型
* nil类型
* t类型
* any类型
* text类型
* kind类型
* 类型类型p
* 将C++的模版语言规范化
* is_same元函数
* 选择结构select
* partition元函数
* 类型串生成元函数mkps
* length元函数
* capacity元函数
* at元函数
* range元函数
* 静态循环(loop)
* 针对PS的静态循环(loop_ps)
* 自动生成函数调用(eloop)
* 针对PS自动生成函数调用(eloop_ps)
* p的其它一些重要的辅助函数
* join元函数
* cut元函数
* count元函数
* index元函数
* exist元函数
* repeat元函数
* resize元函数
* reverse元函数
* replace元函数
* unique元函数
* filter元函数
* map元函数
* reduce元函数
* 自动生成C++类
* scatter类
* tuple结构
* 分析C++类层次
* 分析C++类结构
* 类是否拥有指定参数的成员函数
* 类是否存在指定名称的成员函数
* 类是否存在指定名称的成员变量
* 类是否存在指定名称的子类(型)
* 分析C++重载函数
* 分析函数参数的数量
* 分析函数参数的种类
* 存在的问题
* C++自动化
* 应用篇
* C++静态计算器
* 顺序计算器
* 带括号顺序计算器
* 加减乘除带括号计算器
* 前缀表达式静态计算器
* lambda演算
* 基本LISP解释器
* 基本静态LISP解释器
* 扩展静态LISP解释器
* 静态语言解释器的生成器
* 问题陈述
* 词法分析器
* 语法规则表述
* 语法规则响应器
* 语法分析实现
* 使用前面的LEX和YACC实现静态数据库(SQL)语言
* 观察者模式的C++自动化实现
* 什么是观察者模式
* 观察者模式普通实现
* 观察者模式中的必备元素
* 将观察者模式普通实现自动化
* 将观察者模式标准化
* 一个使用自动化观察者模式的复杂例子
* 撤销和重做(Undo/Redo)的C++自动化实现
* 交换函数swap功能的讨论
* 撤销和重做原理
* 撤销和重做的基本架构
* 将撤销和重做的基本架构模组化
* 处理多类型的对象以及命令管理
* 扩展的框架代码
* 处理复合对象
* 自动化的用户界面(UI)
* 高级篇
* 应用BOOST的MPL库
* 采用OO思想进行框架设计
* 文本编辑器
* 图形用户界面
* 游戏引擎架构

64,668

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧