any、variant

any

  • any的作用:定义一个“能够保存任何类型数据”的变量
    • 类似Python中的:a = 10, a = "Hello"
    • 类似于弱类型语言中的变量,但不完全一样
1
#include <any>
  • 可以直接赋值
1
2
3
4
5
6
std::any test;

// 存储数据就可以直接赋值
test = 1;
test = "Hello";
test = 2.3;
  • 但是不能直接取值
    • std::any:使用std::any_cast<Type>(var)来判断和转换类型
      • Type不是当前var的实际类型,会抛出std::bad_any_cast异常
      • 也可以使用指针和if,判断返回值是否为nullptr
1
2
3
4
5
6
7
8
// 最好使用try-catch,像下面这样
try {
int tmp = std::any_cast<int>(test);
}
// 相当于Python的 except XXExpection as e
catch (std::bad_any_cast& e) {
std::cout << "Not integer." << " " << e.what() << std::endl;
}
1
2
3
4
5
6
7
8
9
10
double* tmp2 = nullptr;
// 因为是指针,所以也要对变量取地址
tmp2 = std::any_cast<double>(&test);

if (tmp2 == nullptr) {
std::cout << "Not double." << std::endl;
}
else {
std::cout << *tmp2 << std::endl;
}
  • any也可以用于引用类型和右值引用
  • any在实际应用中可能遇到可读性问题:因为any在上下文中时编码者不会给出明显的类型提示
    • 参看如下代码:res最后是const char*类型,而不是std::string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::any test = "Hello World!";
try {
std::string res = std::any_cast<std::string>(test);
std::cout << res << std::endl;
}
catch (std::bad_any_cast& e) {
std::cout << "Not std::string." << " " << e.what() << std::endl;
}

try {
const char* res = std::any_cast<const char*>(test);
std::cout << res << std::endl;
}
catch (std::bad_any_cast& e) {
std::cout << "Not const char*." << " " << e.what() << std::endl;
}

variant

  • variant,又称“变体”,作用类似any,但需要提前指定可能会更改的类型
  • 其本质是一个联合体,可以手动使用联合体模拟一个简单版本的variant数据结构
1
2
3
#include <variant>

std::variant<int, double, std::string> test;
  • 与std::any类似,定义之后就可以赋值符合指定的variant类型的值
1
2
test = 1;
test = 2.2;
  • 与std::any类似,std::variant使用std::get<Type>(var)来判断和转换类型
    • Type也可以是下标;
    • Type不是当前var的实际类型,会抛出std::bad_variant_cast异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 取值,最好使用try-catch判断
try {
int tmp = std::get<int>(test);
std::cout << tmp << std::endl;
}
catch (std::bad_variant_access& e) {
std::cout << "Not int." << " " << e.what() << std::endl;
}

try {
double tmp = std::get<double>(test);
std::cout << tmp << std::endl;
}
catch (std::bad_variant_access& e) {
std::cout << "Not double." << " " << e.what() << std::endl;
}

// 这样是不可以的,因为没有float存在
// std::get<float>(test);

// 可以用下标代替尖括号内的内容,0是int,1是double,以此类推
try {
double tmp = std::get<1>(test);
}
catch (std::bad_variant_access& e) {
std::cout << "Not 1." << " " << e.what() << std::endl;
}
  • variant由于编程者手动给出了类型,可以规避上述提到的std::any的问题
1
2
3
4
5
6
7
8
9
10
11
12
std::variant<int, double, std::string> test = "Hello World!";
// 检测其类型
try {
std::string tmp = std::get<std::string>(test);
std::cout << tmp << std::endl;
}
catch (std::bad_variant_access& e) {
std::cout << "Not std::string." << " " << e.what() << std::endl;
}

// 发现此处确实是std::string类型,而不是const char*
// 因此在字符串等处更推荐使用variant
评论