std::optional<T>::optional
来自 cppreference.com
constexpr optional() noexcept; constexpr optional( std::nullopt_t ) noexcept; |
(1) | (自 C++17 起) |
constexpr optional( const optional& other ); |
(2) | (自 C++17 起) |
constexpr optional( optional&& other ) noexcept(/* 见下文 */); |
(3) | (自 C++17 起) |
template < class U > optional( const optional<U>& other ); |
(4) | (自 C++17 起) (自 C++20 起为 constexpr) (条件显式) |
template < class U > optional( optional<U>&& other ); |
(5) | (自 C++17 起) (自 C++20 起为 constexpr) (条件显式) |
template< class... Args > constexpr explicit optional( std::in_place_t, Args&&... args ); |
(6) | (自 C++17 起) |
template< class U, class... Args > constexpr explicit optional( std::in_place_t, |
(7) | (自 C++17 起) |
template < class U = T > constexpr optional( U&& value ); |
(8) | (自 C++17 起) (条件显式) |
构造一个新的 optional 对象。
1) 构造一个不包含值的 optional 对象。
2) 复制构造函数:如果other包含值,则初始化包含的值,就好像直接初始化(但不是直接列表初始化)类型为
T
的对象,其表达式为*other。如果other不包含值,则构造一个不包含值的 optional 对象。- 如果std::is_copy_constructible_v<T>为false,则此构造函数被定义为已删除。
- 如果std::is_trivially_copy_constructible_v<T>为true,则它是一个平凡构造函数。
3) 移动构造函数:如果other包含值,则初始化包含的值,就好像直接初始化(但不是直接列表初始化)类型为
T
的对象,其表达式为std::move(*other),并且不会使other为空:移动后的std::optional
仍然包含值,但值本身已移动。- 除非std::is_move_constructible_v<T>为true,否则此构造函数不参与重载解析。
- 如果std::is_trivially_move_constructible_v<T>为true,则它是一个平凡构造函数。
4) 转换复制构造函数:如果other不包含值,则构造一个不包含值的 optional 对象。否则,构造一个包含值的 optional 对象,就好像直接初始化(但不是直接列表初始化)类型为
T
的对象,其表达式为*other。- 除非满足以下条件,否则此构造函数不参与重载解析
- std::is_constructible_v<T, const U&>为true。
- 如果 `T` 不是(可能是 cv 限定的)bool,`T` 无法从任何类型为(可能是 const)std::optional<U> 的表达式构造或转换,即以下 8 个值都为 false
- 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> 为 false。
5) 转换移动构造函数:如果 other 不包含值,则构造一个不包含值的可选对象。否则,构造一个包含值的可选对象,初始化方式与使用 直接初始化(但不是直接列表初始化)类型为 `T` 的对象时使用表达式 std::move(*other) 相同。
- 除非满足以下条件,否则此构造函数不参与重载解析
- std::is_constructible_v<T, U&&> 为 true。
- 如果 `T` 不是(可能是 cv 限定的)bool,`T` 无法从任何类型为(可能是 const)std::optional<U> 的表达式构造或转换,即以下 8 个值都为 false
- 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> 为 false。
6) 构造一个包含值的可选对象,初始化方式与使用 直接初始化(但不是直接列表初始化)类型为 `T` 的对象时使用参数 std::forward<Args>(args)... 相同。
- 如果 `T` 的选定构造函数是 constexpr 构造函数,则此构造函数是 constexpr 构造函数。
- 除非 std::is_constructible_v<T, Args...> 为 true,否则该函数不参与重载解析。
7) 构造一个包含值的可选对象,初始化方式与使用 直接初始化(但不是直接列表初始化)类型为 `T` 的对象时使用参数 ilist, std::forward<Args>(args)... 相同。
- 如果 `T` 的选定构造函数是 constexpr 构造函数,则此构造函数是 constexpr 构造函数。
- 除非 std::is_constructible_v<T, std::initializer_list<U>&, Args...> 为 true,否则该函数不参与重载解析。
8) 构造一个包含值的可选对象,初始化方式与使用 直接初始化(但不是直接列表初始化)类型为 `T` 的对象时使用表达式 std::forward<U>(value) 相同。
- 如果 `T` 的选定构造函数是 constexpr 构造函数,则此构造函数是 constexpr 构造函数。
- 除非满足以下条件,否则此构造函数不参与重载解析
- std::is_constructible_v<T, U&&> 为 true。
- std::decay_t<U>(until C++20)std::remove_cvref_t<U>(since C++20) 不是 std::in_place_t 也不 是 std::optional<T>.
- 如果 `T` 是(可能是 cv 限定的)bool,std::decay_t<U>(until C++20)std::remove_cvref_t<U>(since C++20) 不是 `std::optional` 的特化。
- 此构造函数为 explicit 当且仅当 std::is_convertible_v<U&&, T> 为 false。
内容 |
[edit] 参数
other | - | 另一个可选对象,其包含的值被复制 |
value | - | 用于初始化包含值的 value |
args... | - | 用于初始化包含值的 arguments |
ilist | - | 用于初始化包含值的 initializer list |
[edit] 异常
2) 抛出 `T` 构造函数抛出的任何异常。
3) 抛出 `T` 构造函数抛出的任何异常。具有以下
noexcept 规范:
noexcept(std::is_nothrow_move_constructible<T>::value)
4-8) 抛出 `T` 构造函数抛出的任何异常。
[edit] 推导指南
[edit] 注释
在解决 LWG issue 3836 之前,从 std::optional<U> 构造 std::optional<bool> 将选择重载 (8) 而不是重载 (4,5),如果 `U` 不是 bool。这是因为如果 `T`(在本例中为 bool)可以从 std::optional<U> 构造或转换,则重载 (4,5) 不参与重载解析,但 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
特性测试 宏 | 值 | Std | 特性 |
---|---|---|---|
__cpp_lib_optional |
202106L | (C++20) (DR20) |
完全 constexpr (4,5) |
[编辑] 示例
运行这段代码
#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>,重载解析 将选择重载 (8) 如果 U 不是 bool |
总是选择 转换复制/移动 在这种情况下构造函数 |
P0602R4 | C++17 | 复制/移动构造函数可能不是平凡的 即使底层构造函数是平凡的 |
需要 传播平凡性 |
P2231R1 | C++20 | 从另一个 std::optional 进行转换构造 (4,5) 是不 constexpr 虽然所需的操作可以在 C++20 中 |
变为 constexpr |
[编辑] 参见
(C++17) |
创建一个 optional 对象(函数模板) |