namespace std {
class any;
也就是说,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操作
函数说明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::any a1; // a1 is empty
如果传递一个值进行初始化,则将其衰减类型用作所包含值的类型:
std::any a2 = 42; // a2 contains value of type int
std::any a3 = "hello"; // a2 contains value of type const char*
要保存与初始值类型不同的类型,必须使用in_place_type标记:
std::any a4{std::in_place_type<long>, 42};
std::any a5{std::in_place_type<std::string>, "hello"};
即使传递给in_place_type的类型也会衰减。下面的声明包含一个const char*:
std::any a5b{std::in_place_type<const char[6]>, "hello"};
要通过多个参数初始化可选对象,必须创建该对象或将std::in_place_type添加为第一个参数(不能推断包含的类型):
std::any a6{std::complex{3.0, 4.0}};
std::any a7{std::in_place_type<std::complex<double>>, 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<std::set<int,decltype(sc)>>, {4, 8, -7, -2, 0, 5}, sc};
注意,还有一个方便的函数make_any<>(),它可以用于单个或多个参数(不需要in_place_type参数)。必须显式指定初始化的类型(如果只传递一个参数,则不会推导出初始化的类型):
auto a10 = std::make_any<float>(3.0);
auto a11 = std::make_any<std::string>("hello");
auto a13 = std::make_any<std::complex<double>>(3.0, 4.0);
auto a14 = 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) // yield copy of the value
std::any_cast<std::string&>(a); // write value by reference
std::any_cast<const std::string&>(a); // read-access by reference
在这里,如果转换失败,将抛出std::bad_any_cast异常。
如果把std::any中所包含的类型转换为移除了传递类型的顶层引用后的类型ID,则转换类型是适合的。如下:
#include <iostream>
#include <string>
#include <any>
int main()
const auto& s = std::make_any<std::string>("hello");
if (s.type() == typeid(std::string))//删除顶层cosnt和引用后的类型
auto a = std::any_cast<std::string>(s);
std::cout << a << std::endl;
return 0;
结果如下:
如果类型不匹配转换失败了,传递一个地址将会返回nullptr:
auto a = std::make_any<std::string>("hello");
std::any_cast<std::string>(&a) // write-access via pointer
std::any_cast<const std::string>(&a); // read-access via pointer
注意,这里转换到引用会导致运行时错误:
std::any_cast<std::string&>(&a); // RUN-TIME ERROR
3. 修改值
相应的赋值和emplace()操作。例如:
#include <iostream>
#include <string>
#include <any>
#include <complex>
int main()
std::any a;
a = 42; // a contains value of type int
a = "hello"; // a contains value of type const char*
a.emplace<std::string>("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 a
s = std::move(std::any_cast<string&>(a)); // move assign string in a to s
与通常的从对象移动的情况一样,在最后一次调用之后,所包含的值a是未指定的。因此,可以使用a作为字符串,只要没有对所包含的字符串值的值做任何假设。
s = std::any_cast<string>(std::move(a));
也可以,但需要一个额外的移动。然而,以下内容是危险的(尽管它是c++标准中的一个例子):
std::any_cast<string&>(a) = std::move(s2); // OOPS: a to hold a string
只有当包含的值已经是字符串时,才可以这样做。如果没有,转换将抛出一个std::bad_any_cast异常。
一般来说,c++是一种具有类型绑定和类型安全性的语言。值对象声明为具有特定类型,该类型定义哪些操作是可能的以及它们的行为方式。值对象不能改变它们的类型。 std: any是一种值类型,它能够更改其类型,同时仍然具有类型安全性。也就是说,对象可以保存任意类型的值,但是它们知道当前保存的值是哪种类型。在声明此类型的对象时,不需要指定可能的类型。 诀窍在于,对象同时拥有包含的...
文章目录前言稍微总结std::variant动机和设计内部实现boostSTLstd::optional动机和设计内部实现boostSTLstd::any动机和设计转换内部实现boostSTL
2021年了。现在回顾一下c++17标准中的std::variant/std::optional/std::any三个库是怎么实现的。
这三个库基本都是实现可选语义:
std::optional:存有T或者不存有值
std::any:存有任意类型值(可以看作带类型信息的void*)
std::var
any是一种很特殊的容器,它只能容纳一个元素,但这个元素可以是任意的类型,可以是基本数据类型(int,double,char,float…)也可以是复合数据类型(类、结构体),那它究竟有什么用?目前来说我没发现什么太大的作用,如果看官发现什么有用的作用,分享一下=.=
操作演示:
#include<iostream>
#include<any>
#include<vector>
#include<set>
using namespace std;
int ma
std::any源码分析
std::any源码分析
std::any构成
std::any的构造函数constexpr any() noexceptany( const any& other )any(any &&__other) noexceptany(T&& value)_S_manage如何保证any_cast的正确性总结
std::any源码分析
std::any构成
sizeof(
std::any) = 16,有一个函数指针和一个_Storage成员组成.
在java或c#中,Object类型对象可以指向任意类型的变量,因为所有的类默认都从Object类继承。但是在c++中,没有类似Object类这样的类型,而很多时候,为了设计出通用的程序,往往需要类似于Object类型作为参数或者返回值。例如,在另一篇文章《c++实现反射类》中就用到了可以指向任意类型的Any类。
在c或者c++中,可以指向任意类型的关键字就是无符号类型void*,任何一...
类型擦除怎么实现的,用类的继承来实现的,为什么类的继承可以实现?
基类是不含模板参数的,派生类中才有模板参数,这个模板参数类型正是赋值的类型,在赋值时,将创建的派生类对象赋值给基类指针,基类的派生类中携带了数据类型,基类只是原始数据的一个占位符,通过多态,它擦除了原始数据类型,因此,任何数据类型都可以赋值给他,从而实现了能存放所有类型数据的目标
为什么要用std::any 而不是 std::variant?
std::variant可以通过声明不同的类型,来变换内部存储的数据,给每种数据都分配了内存空间。
enum中所有变量类型共用同一块内存区域。
使用std::any_cast<typename> 来读取any中的数据。
any很聪明,小类型用enum存,大类型用void*存。
如果传入数据大于32字节,any会创建堆内存new额外存储一次。
不推荐使用std::any,它能做的事情,用std::variant或者std::optio
C++标准库中的std::any是一个类型安全的容器,可以容纳任何类型的值。而std::list则是一个双向链表容器,用于存储一系列元素。
如果想要将一个std::any对象转换为std::list,需要考虑std::any中存储的值类型,因为std::list只能存储特定类型的值。可以使用std::any_cast函数将std::any中的值转换为特定类型,然后将其添加到std::list中。
以下是一个示例代码,将一个std::any对象中的值转换为int类型,并添加到std::list中:
```cpp
#include <any>
#include <list>
#include <iostream>
int main() {
std::any a = 42;
std::list<int> l;
if (a.type() == typeid(int)) {
int value = std::any_cast<int>(a);
l.push_back(value);
for (auto i : l) {
std::cout << i << std::endl;
return 0;
在上面的代码中,首先创建了一个std::any对象a,存储了一个int类型的值。然后创建了一个std::list<int>对象l,用于存储int类型的值。
通过std::any的type函数判断a中存储的值的类型是否为int类型,如果是,则使用std::any_cast函数将其转换为int类型,并添加到std::list中。
最后通过for循环遍历std::list中的元素,并输出到控制台。