千家信息网

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

发表于:2025-01-17 作者:千家信息网编辑
千家信息网最后更新 2025年01月17日,这篇文章主要介绍了C++的std::any怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++的std::any怎么使用文章都会有所收获,下面我们一起来看看吧。一
千家信息网最后更新 2025年01月17日C++的std::any怎么使用

这篇文章主要介绍了C++的std::any怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++的std::any怎么使用文章都会有所收获,下面我们一起来看看吧。

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

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

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

1. 使用std::any

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

std::any a; // a is emptystd::any b = 4.3; // b has value 4.3 of type double a = 42; // a has value 42 of type intb = std::string{"hi"}; // b has value "hi" of type std::string if (a.type() == typeid(std::string)) {    std::string s = std::any_cast(a);    useString(s);}else if (a.type() == typeid(int)) {    useInt(std::any_cast(a));}

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

auto s = std::any_cast(a);

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

try {auto s = std::any_cast(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(a);

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

std::any_cast(a) = "world";

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

auto p = std::any_cast(&a);if (p) {...}

例1:

#include #include  int main(){    std::any i = 42;    const auto ptr = std::any_cast(&i);    if (ptr)    {        std::cout << ptr << std::endl;    }     return 0;}

结果如下:

要清空现有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::any a = "hello"; // type() is const char*if (a.type() == typeid(const char*)) { // true...}if (a.type() == typeid(std::string)) { // false...}std::cout << std::any_cast(v[1]) << '\n'; // OKstd::cout << std::any_cast(v[1]) << '\n'; // EXCEPTION

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

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

例2:

#include #include #include  int main(){    std::vector v;    v.push_back(42);    std::string s = "hello";    v.push_back(s);    for (const auto& a : v) {        if (a.type() == typeid(std::string)) {            std::cout << "string: " << std::any_cast(a) << '\n';        }        else if (a.type() == typeid(int)) {            std::cout << "int: " << std::any_cast(a) << '\n';        }    }}

结果如下:

2. std::any类型和操作

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

2.1 std::any的类型

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

namespace std {class any;}

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

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

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

any对象还可以使用中定义的对象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的新值
reset()销毁any对象的值(使对象为空)
has_value()返回对象是否具有值
type()返回当前类型为std::type_info对象
any_cast()使用当前值作为类型T的值(如果其他类型除外)
swap()交换两个any对象的值

1. 构造函数

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

std::any a1; // a1 is empty

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

std::any a2 = 42; // a2 contains value of type intstd::any a3 = "hello"; // a2 contains value of type const char*

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

std::any a4{std::in_place_type, 42};std::any a5{std::in_place_type, "hello"};

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

std::any a5b{std::in_place_type, "hello"};

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

std::any a6{std::complex{3.0, 4.0}};std::any a7{std::in_place_type>, 3.0, 4.0};

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

// initialize a std::any with a set with lambda as sorting criterion:auto sc = [] (int x, int y) { return std::abs(x) < std::abs(y);}; std::any a8{std::in_place_type>, {4, 8, -7, -2, 0, 5}, sc};

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

auto a10 = std::make_any(3.0);auto a11 = std::make_any("hello");auto a13 = std::make_any>(3.0, 4.0);auto a14 = std::make_any>({4, 8, -7, -2, 0, 5}, sc);

2. 访问值

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

std::any_cast(a) // yield copy of the valuestd::any_cast(a); // write value by referencestd::any_cast(a); // read-access by reference

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

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

#include #include #include  int main(){    const auto& s = std::make_any("hello");        if (s.type() == typeid(std::string))//删除顶层cosnt和引用后的类型    {        auto a = std::any_cast(s);        std::cout << a << std::endl;    }     return 0;}

结果如下:

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

auto a = std::make_any("hello");std::any_cast(&a) // write-access via pointerstd::any_cast(&a); // read-access via pointer

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

std::any_cast(&a); // RUN-TIME ERROR

3. 修改值

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

#include #include #include #include  int main(){    std::any a;    a = 42; // a contains value of type int    a = "hello"; // a contains value of type const char*     a.emplace("hello world");// a contains value of type std::string     return 0;}

结果如下:

4. 移动语法

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

std::string s("hello, world!");std::any a;a = std::move(s); // move s into as = std::move(std::any_cast(a)); // move assign string in a to s

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

注意:

s = std::any_cast(std::move(a));

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

std::any_cast(a) = std::move(s2); // OOPS: a to hold a string

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

关于"C++的std::any怎么使用"这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对"C++的std::any怎么使用"知识都有一定的了解,大家如果还想学习更多知识,欢迎关注行业资讯频道。

类型 对象 函数 字符 字符串 参数 分配 检查 移动 C++ 也就是 也就是说 情况 方法 结果 运行 内容 同时 地址 知识 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 初中起点学网络技术 新型网络技术包括什么 华硕超融合专用服务器 成都磊科网络技术有限公司 数据库技术与 科技与互联网部 目前较流行的软件开发工具 网络技术应用校园网介绍 负载均衡服务器英文 校园网络安全工作如何开展 大方物业收费软件开发 讯飞听见服务器保存时限 杭州启强手机app定制软件开发 无线网络技术与导论实训报告 学校网络安全宣传周新闻报道 安卓联系人数据库详解 软件开发机器人碰撞 在下列数据库中不属于关系型 怎样登录奥维互动地图企业服务器 远程桌面服务器是什么 辽源软件开发定制 软件开发高新技术引入 云主机就是云服务器吗 网络安全与文明的感想 怎么关闭uv网络安全 网络病毒对网络安全的重大影响 职业规划书软件开发师 服务器外汇管理局备案 方舟怎么转非官方服务器 网络安全高中议论文800字左右
0