C++17 Any类

any是一种很特殊的容器,它只能容纳一个元素,但这个元素可以是任意的类型,可以是基本数据类型(int,double,char,float...)也可以是复合数据类型(类、结构体),那它究竟有什么用?目前来说我没发现什么太大的作用,如果看官发现什么有用的作用,分享一下=.=

操作演示:

#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;
	
	return 0;
}

//OutPut:
//69
//8.8
//hello
//world!

首先,VS默认是没有支持C++17的,需要自己修改设置,如果不能使用any,请修改标准

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

any成员:

void reset() : 重置(清空)any对象。

bool has_value() const : 值判断,有值返回true,无值返回false。

const type_info& type() const : 获取类型,返回一个type_info&类的常引用,其成员有类型的哈希值及类型名称(const char*)

void swap(any & other) :与另一个any对象交换“值”。

模板函数(简化版):

template<typename Type>

Type& emplace(Type&& Args) :修改any对象的值。

template<typename Type>

Type* _Cast() :返回any对象值的地址

 

演示

#include<iostream>
#include<any>
using namespace std;

int main() 
{
	any a = 1,b=string("hello");
	cout << a.has_value() << endl;	//true
	a.reset();
	cout << a.has_value() << endl;	//false
	a.emplace<double>(1.1);	//修改值
	a.swap(b);
	cout << a.type().name() << ":" << *a._Cast<string>() << endl;		//string :hello
	cout << b.type().name() << ":" << *b._Cast<double>() << endl;		//double :1.1
	
	return 0;
}

any实现原理:

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

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

取值:只能存,但还无法把元素取出,所以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;
}
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`std::any` 是 C++17 中引入的一个新特性,用于存储任意类型的值,因此如果你要使用 `std::any`,你需要使用 C++17 或更高版本的编译器。 如果你的编译器不支持 C++17,你可以使用其他的实现方式,例如使用模板来实现类似的功能。比如下面这个示例: ```cpp #include <iostream> #include <string> #include <typeindex> #include <unordered_map> #include <stdexcept> class Any { public: Any() : m_tpIndex(std::type_index(typeid(void))) {} Any(const Any& other) : m_ptr(other.Clone()), m_tpIndex(other.m_tpIndex) {} Any(Any&& other) : m_ptr(std::move(other.m_ptr)), m_tpIndex(other.m_tpIndex) {} template<typename T, typename = typename std::enable_if<!std::is_same<typename std::decay<T>::type, Any>::value, T>::type> Any(T&& value) : m_ptr(new Derived<typename std::decay<T>::type>(std::forward<T>(value))), m_tpIndex(typeid(typename std::decay<T>::type)) {} bool IsNull() const { return !bool(m_ptr); } template<class T> bool Is() const { return m_tpIndex == std::type_index(typeid(T)); } template<class T> typename std::decay<T>::type& AnyCast() { if (!Is<T>()) { throw std::runtime_error("can not cast " + std::string(m_tpIndex.name()) + " to " + std::string(typeid(T).name())); } auto derived = dynamic_cast<Derived<typename std::decay<T>::type>*>(m_ptr.get()); return derived->m_value; } Any& operator = (const Any& other) { if (m_ptr == other.m_ptr) { return *this; } m_ptr = other.Clone(); m_tpIndex = other.m_tpIndex; return *this; } private: struct Base { virtual ~Base() {} virtual std::unique_ptr<Base> Clone() const = 0; }; template<typename T> struct Derived : Base { template<typename U> Derived(U&& value) : m_value(std::forward<U>(value)) { } std::unique_ptr<Base> Clone() const { return std::unique_ptr<Base>(new Derived<T>(m_value)); } T m_value; }; private: std::unique_ptr<Base> Clone() const { if (m_ptr != nullptr) { return m_ptr->Clone(); } return nullptr; } std::unique_ptr<Base> m_ptr; std::type_index m_tpIndex; }; int main() { Any a = 1; std::cout << a.AnyCast<int>() << std::endl; a = std::string("hello"); std::cout << a.AnyCast<std::string>() << std::endl; try { a.AnyCast<int>(); } catch (const std::exception& e) { std::cout << e.what() << std::endl; } return 0; } ``` 这段代码定义了一个 `Any` 类,使用模板参数来存储任意类型的值,并在运行时动态判断类型。你可以像使用 `std::any` 一样使用 `Any` 类型的变量,例如调用 `AnyCast` 方法来获取存储的值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值