std::optional<T>::optional
来自 cppreference.cn
constexpr optional() noexcept; |
(1) | (since C++17) |
constexpr optional( std::nullopt_t ) noexcept; |
(2) | (since C++17) |
constexpr optional( const optional& other ); |
(3) | (since C++17) |
constexpr optional( optional&& other ) noexcept(/* see below */); |
(4) | (since C++17) |
template< class U > optional( const optional<U>& other ); |
(5) | (since C++17) (constexpr since C++20) (conditionally explicit) |
template< class U > optional( optional<U>&& other ); |
(6) | (since C++17) (constexpr since C++20) (conditionally explicit) |
template< class... Args > constexpr explicit optional( std::in_place_t, Args&&... args ); |
(7) | (since C++17) |
template< class U, class... Args > constexpr explicit optional( std::in_place_t, |
(8) | (since C++17) |
template< class U = std::remove_cv_t<T> > constexpr optional( U&& value ); |
(9) | (since C++17) (conditionally explicit) |
构造一个新的 optional 对象。
目录 |
[编辑] 参数
other | - | 另一个 optional 对象,其包含的值将被复制 |
value | - | 用于初始化包含值的值 |
args... | - | 用于初始化包含值的参数 |
ilist | - | 用于初始化包含值的初始化列表 |
[编辑] 效果
重载 | 初始化方法 | 包含值的初始化器 | has_value() 构造后 |
---|---|---|---|
(1) | N/A | - | false |
(2) | |||
(3) | 直接 (非列表) | *other | other.has_value()
|
(4) | std::move(*other) | ||
(5) | *other | ||
(6) | std::move(*other) | ||
(7) | std::forward<Args>(args)... | true | |
(8) | ilist, std::forward<Args>(args)... | ||
(9) | std::forward<U>(value) |
[编辑] 约束和补充信息
如果 std::is_trivially_copy_constructible_v<T> 为 true,则构造函数是平凡的。
如果 std::is_trivially_move_constructible_v<T> 为 true,则构造函数是平凡的。
5) 仅当满足以下所有条件时,此重载才参与重载解析
- std::is_constructible_v<T, const U&> 为 true。
- 如果
T
不是(可能带有 cv 限定符的)bool,则以下 8 个值均为 false[1]- std::is_constructible_v<T, std::optional<U>&>
- std::is_constructible_v<T, const std::optional<U>&>
- std::is_constructible_v<T, std::optional<U>&&>
- std::is_constructible_v<T, const std::optional<U>&&>
- std::is_convertible_v<std::optional<U>&, T>
- std::is_convertible_v<const std::optional<U>&, T>
- std::is_convertible_v<std::optional<U>&&, T>
- std::is_convertible_v<const std::optional<U>&&, T>
此重载声明为如同 explicit(!std::is_convertible_v<const U&, T>)。
6) 仅当满足以下所有条件时,此重载才参与重载解析
- std::is_constructible_v<T, U> 为 true。
- 如果
T
不是(可能带有 cv 限定符的)bool,则以下 8 个值均为 false[1]- std::is_constructible_v<T, std::optional<U>&>
- std::is_constructible_v<T, const std::optional<U>&>
- std::is_constructible_v<T, std::optional<U>&&>
- std::is_constructible_v<T, const std::optional<U>&&>
- std::is_convertible_v<std::optional<U>&, T>
- std::is_convertible_v<const std::optional<U>&, T>
- std::is_convertible_v<std::optional<U>&&, T>
- std::is_convertible_v<const std::optional<U>&&, T>
此重载声明为如同 explicit(!std::is_convertible_v<U, T>)。
如果为初始化选择的
T
的构造函数是 constexpr 构造函数,则此构造函数也是 constexpr 构造函数。 如果为初始化选择的
T
的构造函数是 constexpr 构造函数,则此构造函数也是 constexpr 构造函数。9) 仅当满足以下所有条件时,此重载才参与重载解析
- std::is_constructible_v<T, U> 为 true。
- std::decay_t<U>(C++20 前)std::remove_cvref_t<U>(C++20 起) 既不是 std::in_place_t 也不是 std::optional<T>。
- 如果
T
是(可能带有 cv 限定符的)bool,std::decay_t<U>(C++20 前)std::remove_cvref_t<U>(C++20 起) 不是std::optional
的特化。
此重载声明为如同 explicit(!std::is_convertible_v<U, T>)。
如果为初始化选择的
T
的构造函数是 constexpr 构造函数,则此构造函数也是 constexpr 构造函数。- ↑ 1.0 1.1 换句话说,
T
既不能从类型为(可能带有 const 限定符的)std::optional<U> 的任何表达式构造,也不能转换。
[编辑] 异常
3) 抛出 T 的构造函数抛出的任何异常。
4) 抛出 T 的构造函数抛出的任何异常。具有以下
noexcept 规范:
noexcept(std::is_nothrow_move_constructible<T>::value)
5-9) 抛出 T 的构造函数抛出的任何异常。
[编辑] 推导指引
[编辑] 注释
在 LWG issue 3836 解决之前,如果 U 不是 bool,则从 std::optional<U> 构造 std::optional<bool> 会选择重载 (9) 而不是重载 (5,6)。这是因为如果 T(在本例中为 bool)可以从 std::optional<U> 构造或转换,则重载 (5,6) 不参与重载解析,但是 std::optional::operator bool
使任何 U
都有可能进行转换。
因此,构造的 std::optional<bool> 始终包含一个值。该值由提供的 std::optional<U> 对象是否包含值决定,而不是从包含值直接初始化的 bool 值
std::optional<bool> op_false(false); std::optional<int> op_zero(0); std::optional<int> from_bool(op_false); // OK: contains 0 (initialized from false) std::optional<bool> from_int(op_zero); // DEFECT (LWG 3836): contains true because // op_zero contains a value, even if initializing // bool from that value gives false
特性测试 宏 | 值 | 标准 | 特性 |
---|---|---|---|
__cpp_lib_optional |
202106L |
(C++20) (DR20) |
完全 constexpr (5,6) |
[编辑] 示例
运行此代码
#include <iostream> #include <optional> #include <string> int main() { std::optional<int> o1, // empty o2 = 1, // init from rvalue o3 = o2; // copy-constructor // calls std::string( initializer_list<CharT> ) constructor std::optional<std::string> o4(std::in_place, {'a', 'b', 'c'}); // calls std::string( size_type count, CharT ch ) constructor std::optional<std::string> o5(std::in_place, 3, 'A'); // Move-constructed from std::string using deduction guide to pick the type std::optional o6(std::string{"deduction"}); std::cout << *o2 << ' ' << *o3 << ' ' << *o4 << ' ' << *o5 << ' ' << *o6 << '\n'; }
输出
1 1 abc AAA deduction
[编辑] 缺陷报告
以下行为变更缺陷报告已追溯应用于先前发布的 C++ 标准。
DR | 应用于 | 已发布行为 | 正确行为 |
---|---|---|---|
LWG 3836 | C++17 | 当构造 std::optional<bool> 时 从 std::optional<U>,重载解析 如果 U 不是 bool,则会选择重载 (9) |
始终选择 在这种情况下始终选择转换复制/移动构造函数 构造函数 |
LWG 3886 | C++17 | 重载 (9) 的默认模板参数是 T | 更改为 std::remove_cv_t<T> |
P0602R4 | C++17 | 即使底层构造函数是平凡的,复制/移动构造函数也可能不是平凡的 即使底层构造函数是平凡的,复制/移动构造函数也可能不是平凡的 |
需要 需要传播平凡性 |
P2231R1 | C++20 | 来自另一个 std::optional 的重载 (5,6) 不是 constexpr | 变为 constexpr |
[编辑] 参见
(C++17) |
创建一个 optional 对象 (函数模板) |