std::optional<T>是 C++17 中的一个标准库组件,optional <T>对象默认是空的,也就是处于无效状态,给它赋值后因为里面有了元素,就变成了有效状态。
1.引入背景
c++函数常用返回值表示函数是否执行成功。如返回nullptr表示执行失败,反之则执行成功。或者返回-1表示执行失败,0表示执行成功。此时,如果函数在执行成功时,还需要传出执行结果,则只能使用函数的传出参数。
我们需要有一种简单的概念,它能够将执行是否成功的标记与执行结果统一起来,这就是模板类 optional。
2.创建对象
std::optional<T> 包含一个值时,它的行为就像一个普通的容器,可以访问和修改这个值。当它为空时,任何试图访问值的操作都会失败,通常是通过抛出一个异常或返回一个错误值。
下面例子中,初始化optional<int>对象后,使用函数 has_value()检查是否包含值,使用函数value() 访问包含的值。
#include <iostream>
#include <optional>
using namespace std;
int main()
{
optional<int> op1; // 默认是无效值
if (op1.has_value())
{
cout << "op1 value = " << op1.value() << endl;
}
optional<int> op2 = 10; // 赋值,持有有效值
if (op2.has_value())
{
cout << "op2 value = " << op2.value() << endl;
}
}
运行结果:
op2 value = 10
optional也能够转换为 bool 值,可以用 */-> 来直接访问内部的值,行为表现很像指针。
#include <iostream>
#include <string>
#include <optional>
using namespace std;
int main()
{
optional<string> op {"c++ shell"};
if (op) //可以转为bool值
{
cout << "op value = " << *op << endl; // 使用*/->访问内部的值
}
}
运行结果:
op value = c++ shell
3.工厂函数
optional 也可以用工厂函数 make_optional() 来创建,不过与直接构造不同,即使不提供初始化参数,它也必定会用“零值”创建出一个有效值的 optional 对象,这一点我们在用的时候要特别注意。
#include <iostream>
#include <vector>
#include <optional>
using namespace std;
int main()
{
auto op1 = make_optional<int>(); // 使用默认值构造有效值
if (op1.has_value())
{
cout << "op1 value = " << op1.value() << endl;
}
auto op2 = make_optional<std::vector<double>>(); // 使用默认值构造有效值
if (op2.has_value())
{
cout << "op2 size = " << op2->size() << endl;
}
}
运行结果:
op1 value = 0
op2 size = 0
4.应用示例
实现一个求平方根的函数。
#include <iostream>
#include <optional>
using namespace std;
optional<double> safesqrt(double x)
{
optional<double> v;
if (x < 0) {
return v;
}
v = ::sqrt(x);
return v;
}
int main()
{
optional<double> v1 = safesqrt(-1);
if (v1.has_value())
{
cout << "v1 value = " << v1.value() << endl;
}
optional<double> v2 = safesqrt(3);
if (v2.has_value())
{
cout << "v2 size = " << v2.value() << endl;
}
};
运行结果
v2 size = 1.73205