天天看点

C++17 any类(万能容器)详解

一、any是什么?

1、any“不是”模板类,any是一种很特殊的容器。

2、any只能容纳一个元素,但这个元素可以是任意的类型,可以是基本数据类型(int、double、string、标准容器或者任何自定义类型)。

3、一种动态(类型检查只发生在运行时)语言特性的数据结构。

4、C++17引入,需要RIIT支持,VS默认是没有支持C++17的,需要自己修改设置,如果不能使用any,请修改标准。

VS修改C++标准(支持C++17)

二、any类摘要

class any
{
public:
	any();									//默认构造
	any(const any& _That);					//拷贝构造
	template<class _ValueType>
		any(_ValueType&& _Value);
	~any();									//析构
	any& operator=(const any& _That);		//拷贝复制
	void reset();							//清空内容
	void swap(any& _That);					//交换语义
	bool has_value() const;					//是否持有值
	const type_info& type() const;			//获取类型信息
	template<class _Decayed>
	_Decayed * _Cast();						//若*this包含_decay类型的值,返回一个指向它的指针
};

//辅助函数
void swap(any& _Left, any& _Right);			//交换语义
template<class _ValueType,class... _Types>
inline any make_any(_Types&&... _Args);		//工厂函数
template<class _Ty>
_Ty any_cast(const any& _Any);				//访问元素,运行时类型检查,不一致则抛出bad_any_cast异常。并且含有多个重载版本。
           

C++typeid关键字详解:

https://kernel.blog.csdn.net/article/details/50947821

三、any类用法

#include<iostream>
#include<any>
#include<vector>
#include<set>
using namespace std;
int main() {
	any Int = 69,		//整型
		Double = 8.8,	//浮点型
		CStr = "hello",			//字符数组
		Str = string("world!");		//string类
	vector<any> anys = { Int,Double,CStr,Str };	//可直接放入序列容器中
	//set < any > any_set{ Int,Double,CStr,Str };	//Error:不能直接放入关联容器内,需要提供operator<,但 any 很难比较
	cout << *Int._Cast<int>() << endl;	//T* _Cast<typenampe T>():返回any对象的"值",但需要一个模板参数确定对象值的类型
	cout << *Double._Cast<double>() << endl;
	cout << *CStr._Cast<char const *>() << endl;
	cout << *Str._Cast<string>() << endl;
	
	std::any any = std::make_any<int>(10);
	if (typeid(int) == any.type())
		int i = std::any_cast<int>(any);
	//double d = std::any_cast<double >(any);	//抛出bad_any_cast异常
	return 0;
}
//OutPut:
//69
//8.8
//hello
//world!
           

注意:

any的析构函数删除内部holder对象。如果类型是指针,any并不会对指针执行delete操作,所有any保存原始指针对造成内存泄漏。完美解决方法是用共享智能指针std::shared_ptr< T >包装存入any容器。

四、any实现原理:

通过使用模板构造函数擦除模板类的参数类型。

1、存储:

定义一个基类Base,再派生一个模板类Data,对二者再进行一次封装,构造一个Any类,使用Any类的模板构造函数来构造一个Data对象,这样就能存储任何数据类型。

2、取值:

只能存,但还无法把元素取出,所以Any必须有一个基类Base指针的成员变量,存储构造好的Data对象,使用模板函数_Cast(),利用其模板参数Type,进行一个再将Base类强制转换为Data< Type > 对象。

基本上是这个原理吧。

附超简版代码:

#include<iostream>
#include<any>
using namespace std;
class Any {
public:
	template<typename T>
	Any(T t) :base(new Data<T>(t)) {}		//模板构造函数
	template<typename T>
	T _Cast() {
		return dynamic_cast<Data<T>*>(base.get())->value;		//强制转换
	}
private:
	class Base {
	public:
		virtual ~Base() {}		//确定Base为多态类型
	};
	template <typename T>
	class Data :public Base {
	public:
		Data(T t) :value(t) {}
		T value;
	};
	unique_ptr<Base> base;					//基类指针
};
int main() {
	Any a(string("s123")), b = 1, c = 12.0;
	cout << a._Cast<string>() << endl;			/*调用get函数必须要填写模板参数,我感觉这样大大折扣了any的作用*/
	cout << b._Cast<int>() << endl;				/*我想能否在构造的时候就确认参数的类型,保证_Cast调用的时候不需要使用模板参数*/
	cout << c._Cast<double>();
	return 0;
}
           

参考文章:

C++中VS2019下STL的std::any深入剖析:

C++17 any类(万能容器)详解:

Boost中的容器boost::any

相关文章推荐:

initialize(initialize_list<T>)

c++11 Variadic Templates(…)(可变参数列表)

元组tuple

C++17之std::variant

C++17:std::any, std::variant 和 std::optional

Qt之QVariant用法

QVariant的用法

如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)

更多内容请关注个人博客:https://blog.csdn.net/qq_43148810