C++的std::any怎么使用(C++,开发技术)

时间:2024-05-04 06:52:02 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

一般来说,c++是一种具有类型绑定和类型安全性的语言。值对象声明为具有特定类型,该类型定义哪些操作是可能的以及它们的行为方式。值对象不能改变它们的类型。

std: any是一种值类型,它能够更改其类型,同时仍然具有类型安全性。也就是说,对象可以保存任意类型的值,但是它们知道当前保存的值是哪种类型。在声明此类型的对象时,不需要指定可能的类型。

诀窍在于,对象同时拥有包含的值和使用typeid包含值的类型。因为这个值可以有任何大小,所以可以在堆上分配内存,鼓励实现避免小对象的动态分配。也就是说,如果分配一个字符串,对象将为该值分配内存并复制该字符串,同时也在内部存储分配的字符串。稍后,可以执行运行时检查来确定当前值的类型,并使用any_cast<该值的类型>获取值。

1. 使用std::any

下面的例子演示了std::any:

std::anya;//aisemptystd::anyb=4.3;//bhasvalue4.3oftypedoublea=42;//ahasvalue42oftypeintb=std::string{"hi"};//bhasvalue"hi"oftypestd::stringif(a.type()==typeid(std::string)){std::strings=std::any_cast<std::string>(a);useString(s);}elseif(a.type()==typeid(int)){useInt(std::any_cast<int>(a));}

可以声明std::any为空或由特定类型的值初始化。初始值的类型成为所包含值的类型。通过使用成员函数type(),可以根据任何类型的类型ID检查所包含值的类型。如果对象是空的,对象类型ID是typeid(void)。要访问包含的值,可以通过std::any_cast<对象类型>的方式:

autos=std::any_cast<std::string>(a);

如果转换失败,因为对象为空或包含的类型不匹配,则抛出std::bad_any_cast。因此,在不检查或不知道类型的情况下,最好实现以下功能:

try{autos=std::any_cast<std::string>(a);...}catch(std::bad_any_cast&e){std::cerr<<"EXCEPTION:"<<e.what()<<'\n';}

注意,std::any_cast<>创建了一个传递类型的对象。如果将std::string作为模板参数传递给std::any_cast<>,它将创建一个临时string(一个prvalue),然后用它初始化新对象s。如果没有这样的初始化,通常最好转换为引用类型,以避免创建临时对象:

std::cout<<std::any_cast<conststd::string&>(a);

要修改该值,需要转换为对应的引用类型:

std::any_cast<std::string&>(a)="world";

还可以为std::any对象的地址调用std::any_cast。在这种情况下,如果类型匹配,则强制转换返回相应的地址指针;如果不匹配,则返回nullptr:

autop=std::any_cast<std::string>(&a);if(p){...}

例1:

#include<iostream>#include<any>intmain(){std::anyi=42;constautoptr=std::any_cast<int>(&i);if(ptr){std::cout<<ptr<<std::endl;}return0;}

结果如下:

C++的std::any怎么使用

要清空现有std::任何可以调用的对象:

方法1:a.reset(); // makes it empty

方法2:a = std::any{};

方法3:a = {};

可以直接检查对象是否为空:

if(a.has_value()){...}

还要注意,值是使用衰减类型存储的(数组转换为指针,忽略顶层引用和const)。对于字符串常量,这意味着值类型是const char*。要检查type()并使用std::any_cast<>,必须使用以下类型:

std::anya="hello";//type()isconstchar*if(a.type()==typeid(constchar*)){//true...}if(a.type()==typeid(std::string)){//false...}std::cout<<std::any_cast<constchar*>(v[1])<<'\n';//OKstd::cout<<std::any_cast<std::string>(v[1])<<'\n';//EXCEPTION

std::any没有定义比较运算符(因此,不能比较或排序对象),没有定义hash函数,也没有定义value()成员函数。由于类型只在运行时才知道,所以不能使用泛型lambdas处理与类型无关的当前值。总是需要运行时函数std::any_cast<>来处理当前值。

然而,可以将std::任何对象放入容器中。

例2:

#include<iostream>#include<vector>#include<any>intmain(){std::vector<std::any>v;v.push_back(42);std::strings="hello";v.push_back(s);for(constauto&a:v){if(a.type()==typeid(std::string)){std::cout<<"string:"<<std::any_cast<conststd::string&>(a)<<'\n';}elseif(a.type()==typeid(int)){std::cout<<"int:"<<std::any_cast<int>(a)<<'\n';}}}

结果如下:

C++的std::any怎么使用

2. std::any类型和操作

本节详细描述std::any的类型和操作。

2.1 std::any的类型

在头文件<any>中,c++标准库定义了类std::any,如下所示:

namespacestd{classany;}

也就是说,std::any根本不是类模板。

此外,定义了以下类型和对象:

如果类型转换失败,则抛出异常类型std::bad_any_cast,它派生自std::bad_cast,而std::bad_cast派生自std::exception。

any对象还可以使用<utility>中定义的对象std::in_place_type(类型为std::in_place_type_t)。

2.2 std::any操作

std::any操作

std::any操作函数说明constructors创建一个any对象(可能调用底层类型的构造函数)make_any()创建一个any对象(传递值来初始化它)destructor销毁any对象=分配一个新值emplace<T>()分配一个类型为T的新值reset()销毁any对象的值(使对象为空)has_value()返回对象是否具有值type()返回当前类型为std::type_info对象any_cast<T>()使用当前值作为类型T的值(如果其他类型除外)swap()交换两个any对象的值

1. 构造函数

默认情况下,std::any的初始值为空。

std::anya1;//a1isempty

如果传递一个值进行初始化,则将其衰减类型用作所包含值的类型:

std::anya2=42;//a2containsvalueoftypeintstd::anya3="hello";//a2containsvalueoftypeconstchar*

要保存与初始值类型不同的类型,必须使用in_place_type标记:

std::anya4{std::in_place_type<long>,42};std::anya5{std::in_place_type<std::string>,"hello"};

即使传递给in_place_type的类型也会衰减。下面的声明包含一个const char*:

std::anya5b{std::in_place_type<constchar[6]>,"hello"};

要通过多个参数初始化可选对象,必须创建该对象或将std::in_place_type添加为第一个参数(不能推断包含的类型):

std::anya6{std::complex{3.0,4.0}};std::anya7{std::in_place_type<std::complex<double>>,3.0,4.0};

甚至可以传递一个初始化器列表,后面跟着附加的参数:

//initializeastd::anywithasetwithlambdaassortingcriterion:autosc=[](intx,inty){returnstd::abs(x)<std::abs(y);};std::anya8{std::in_place_type<std::set<int,decltype(sc)>>,{4,8,-7,-2,0,5},sc};

注意,还有一个方便的函数make_any<>(),它可以用于单个或多个参数(不需要in_place_type参数)。必须显式指定初始化的类型(如果只传递一个参数,则不会推导出初始化的类型):

autoa10=std::make_any<float>(3.0);autoa11=std::make_any<std::string>("hello");autoa13=std::make_any<std::complex<double>>(3.0,4.0);autoa14=std::make_any<std::set<int,decltype(sc)>>({4,8,-7,-2,0,5},sc);

2. 访问值

要访问包含的值,必须使用std::any_cast<>将其转换为其类型。将该值转换为一个字符串,有几个选项:

std::any_cast<std::string>(a)//yieldcopyofthevaluestd::any_cast<std::string&>(a);//writevaluebyreferencestd::any_cast<conststd::string&>(a);//read-accessbyreference

在这里,如果转换失败,将抛出std::bad_any_cast异常。

如果把std::any中所包含的类型转换为移除了传递类型的顶层引用后的类型ID,则转换类型是适合的。如下:

#include<iostream>#include<string>#include<any>intmain(){constauto&s=std::make_any<std::string>("hello");if(s.type()==typeid(std::string))//删除顶层cosnt和引用后的类型{autoa=std::any_cast<std::string>(s);std::cout<<a<<std::endl;}return0;}

结果如下:

C++的std::any怎么使用

如果类型不匹配转换失败了,传递一个地址将会返回nullptr:

autoa=std::make_any<std::string>("hello");std::any_cast<std::string>(&a)//write-accessviapointerstd::any_cast<conststd::string>(&a);//read-accessviapointer

注意,这里转换到引用会导致运行时错误:

std::any_cast<std::string&>(&a);//RUN-TIMEERROR

3. 修改值

相应的赋值和emplace()操作。例如:

#include<iostream>#include<string>#include<any>#include<complex>intmain(){std::anya;a=42;//acontainsvalueoftypeinta="hello";//acontainsvalueoftypeconstchar*a.emplace<std::string>("helloworld");//acontainsvalueoftypestd::stringreturn0;}

结果如下:

C++的std::any怎么使用

4. 移动语法

std: any也支持移动语义。但是,请注意,move语义必须满足包含的类型具有可复制构造函数。也就是说,不支持只移动类型作为包含值类型。处理move语义的最佳方法可能并不明显。所以,你应该这样做:

std::strings("hello,world!");std::anya;a=std::move(s);//movesintoas=std::move(std::any_cast<string&>(a));//moveassignstringinatos

与通常的从对象移动的情况一样,在最后一次调用之后,所包含的值a是未指定的。因此,可以使用a作为字符串,只要没有对所包含的字符串值的值做任何假设。

注意:

s=std::any_cast<string>(std::move(a));

也可以,但需要一个额外的移动。然而,以下内容是危险的(尽管它是c++标准中的一个例子):

std::any_cast<string&>(a)=std::move(s2);//OOPS:atoholdastring

只有当包含的值已经是字符串时,才可以这样做。如果没有,转换将抛出一个std::bad_any_cast异常。

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:C++的std::any怎么使用的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:Angular中zone.js的工作原理是什么下一篇:

7 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18