精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
服务方向
联系方式
锐英源精品原创,禁止转载和任何形式的非法内容使用,违者必究。点名“简易百科”和“闲暇巴”盗用锐英源原创内容。
C++17新增数据类型byte、variant、optional和any的第一感觉是C++越来越不像强类型语言了,这个转变可能初学者不好接受,variant像联合又像MFC的COleVariant,但又不是,optional是可有可无的意思,any就彻底像C#的Type基类了,总之觉得C++标准团队也是在学其它语言,让C++与时俱进,但变的越来越复杂,复杂是因为旧的原始模式不能废除,旧的模式和新的模式就像两条路,不过新增数据类型有适用场合,大家也只有坚持学习了。
在 C++17 中,标准库中添加了许多新的和有用的数据类型,其中一些源自 Boost。
std::byte
std::byte表示单个字节。开发人员传统上使用 char(signed or unsigning) 来表示字节,但现在有一种类型不仅可以是字符或整数。
但是,std::byte可以转换为整数,反之亦然。该std::byte类型旨在与数据仓库交互,不支持算术运算,尽管它支持按位运算。
为了说明上述内容,我们来看一下以下代码:
#include <iostream>
#include <cstddef>
void PrintValue(const std::byte& b) {
std::cout << "current byte value is " << std::to_integer<int>(b) << std::endl;
}
int main() {
std::byte bt {2};
std::cout << "initial value of byte is " << std::to_integer<int>(bt) << std::endl;
bt <<= 2;
PrintValue(bt);
}
std::variant 是一个类型安全的联合,它包含给定时间的替代类型之一的值(这里不能有引用、数组或 'void')。
一个简单的示例:假设有一些数据,其中某个公司可以表示为 an ID或 a string,并带有该公司的全名。此类信息可以使用包含std ::variant无符号整数或 string来表示。通过将整数分配给 std::variable,我们设置值,然后我们可以使用 std::get提取它,如下所示:
#include <iostream>
#include <variant>
int main() {
std::variant<uint32_t, std::string> company;
company = 1001;
std::cout << "The ID of company is " << std::get<uint32_t>(company) << std::endl;
return 0;
}
如果我们尝试使用不是以这种方式定义的成员(例如std::get<std::string>(company),),程序将引发异常。
为什么使用std::variant而不是通常的联合?这主要是因为联合在语言中存在主要是为了与 C 兼容,并且不适用于非 POD 类型的对象。
这尤其意味着,将具有自定义复制构造函数和析构函数的成员放在联合中并不容易。对于 std::variant,则没有此类限制。
std::optional
std::optional类型是一个对象,它可能包含也可能不包含值;当函数无法返回值时,此对象可用作函数的返回值,这很有用且方便;然后,它用作null指针的替代项。当使用 optional 时,我们获得了一个额外的优势:现在函数失败的可能性直接在声明中明确表示,并且由于我们必须从 optional 中提取值,因此我们意外使用null值的概率大大降低。
让我们看一下以下示例:
#include <iostream>
#include <string>
#include <optional>
std::optional<int> StrToInt(const std::string& s) {
try {
int val = std::stoi(s);
return val;
}
catch (std::exception&) {
return {};
}
}
int main() {
int good_value = StrToInt("689").value_or(0);
std::cout << "StrToInt(""689"") returns " << good_value << std::endl;
int bad_value = StrToInt("hfjkhjjkgdsd").value_or(0);
std::cout << "StrToInt(""hfjkhjjkgdsd"") returns " << bad_value << std::endl;
return 0;
}
上面的示例显示了一个尝试将StrToInt转换为整数的函数。通过返回std::optional,该StrToInt函数留下了可以传递 invalid string的可能性,该 invalid string无法转换。在main中,我们使用value_or()函数从std::optional中获取值,如果函数失败,则返回默认值零(如果转换失败)。
std::any
C++17 的另一个新增功能是std::any类型 . std::any为任何类型的单个值提供类型安全容器,并提供允许您执行类型安全验证的工具。
让我们看一下以下示例:
C++
#include <any>
#include <utility>
#include <iostream>
#include <vector>
int main() {
std::vector<std::any> v { 10, 20.2, true, "Hello world!" };
for (size_t i = 0; i < v.size(); i++) {
auto& t = v[i].type();
if (t == typeid(int)) {
std::cout << "Index of vector : " << i << " Type of value : 'int'\n";
}
else if (t == typeid(double)) {
std::cout << "Index of vector : " << i << " Type of value : 'double'\n";
}
else if (t == typeid(bool)) {
std::cout << "Index of vector : " << i << " Type of value : 'bool'\n";
}
else if (t == typeid(char *)) {
std::cout << "Index of vector : " << i << " Type of value : 'char *'\n";
}
}
std::cout << "\n std::any_cast<double>(v[1]) = " << std::any_cast<double>(v[1])
<< std::endl;
return 0;
}
在上面的代码中,在循环中,我们传递 std::vector<std::any>元素 .在每次迭代中,我们提取向量的一个元素,然后尝试确定std::any值的实际类型。
请注意,std::any_cast<T>(val) 返回在'val' 中内部值T的副本。如果我们需要获取引用以避免复制复杂对象,则需要使用any_cast<T&>(val) construct。
但是double类型不是一个复杂的对象,因此我们可以负担得起一个副本。这正是我们在上面代码的倒数第二行所做的,其中我们访问了 v [1] double类型的对象。
any就是MFC里的COleVariant,可以保存所有类型的数据,有VT_TYPE属性成员。