std::optional<T>::optional
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(/* see below */);
|
(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,
std::initializer_list<U> ilist,
Args&&... args );
|
(7) | (C++17 起) |
template < class U = std::remove_cv_t<T> >
constexpr optional( U&& value );
|
(8) | (C++17 起) (有条件地显式) |
构造一个新的 optional 对象。
other 包含值,则初始化所含值,如同直接初始化(但不是直接列表初始化)一个类型为 T 的对象,其初始化器为表达式 *other。如果 other 不包含值,则构造一个不含值的对象。
- 如果
std::is_copy_constructible_v<T>是false,则此构造函数被定义为弃置的。 - 如果
std::is_trivially_copy_constructible_v<T>是true,则它是平凡构造函数。
other 包含值,则初始化所含值,如同直接初始化(但不是直接列表初始化)一个类型为 T 的对象,其初始化器为表达式 std::move(*other),并且不会使 other 为空:被移动后的 std::optional 仍包含一个值,但该值本身已被移动。如果 other 不包含值,则构造一个不含值的对象。
- 除非
std::is_move_constructible_v<T>是true,否则此构造函数不参与重载决议。 - 如果
std::is_trivially_move_constructible_v<T>是true,则它是平凡构造函数。
other 不包含值,则构造一个不含值的 optional 对象。否则,构造一个包含值的 optional 对象,该值初始化方式如同直接初始化(但不是直接列表初始化)一个类型为 T 的对象,其初始化器为表达式 *other。
- 此构造函数仅在满足以下条件时参与重载决议:
std::is_constructible_v<T, const U&>是true。- 如果
T不是(可能有 cv 限定)bool,则T不能从任何类型为(可能有const)std::optional<U>的表达式构造或转换,即converts_from_any_cvref<T, std::optional<U>>是false,其中converts_from_any_cvref如下所述。
- 此构造函数是
explicit,当且仅当std::is_convertible_v<const U&, T>是false。
other 不包含值,则构造一个不含值的 optional 对象。否则,构造一个包含值的 optional 对象,该值初始化方式如同直接初始化(但不是直接列表初始化)一个类型为 T 的对象,其初始化器为表达式 std::move(*other)。
- 此构造函数仅在满足以下条件时参与重载决议:
std::is_constructible_v<T, U&&>是true。- 如果
T不是(可能有 cv 限定)bool,则T不能从任何类型为(可能有const)std::optional<U>的表达式构造或转换,即converts_from_any_cvref<T, std::optional<U>>是false,其中converts_from_any_cvref如下所述。
- 此构造函数是
explicit,当且仅当std::is_convertible_v<U&&, T>是false。
T 的对象,参数为 std::forward<Args>(args)...。
- 如果
T的被选构造函数是constexpr构造函数,则此构造函数是constexpr构造函数。 - 除非
std::is_constructible_v<T, Args...>是true,否则该函数不参与重载决议。
T 的对象,参数为 ilist, std::forward<Args>(args)...。
- 如果
T的被选构造函数是constexpr构造函数,则此构造函数是constexpr构造函数。 - 除非
std::is_constructible_v<T, std::initializer_list<U>&, Args...>是true,否则该函数不参与重载决议。
T 的对象,其初始化器为表达式 std::forward<U>(value)。
- 如果
T的被选构造函数是constexpr构造函数,则此构造函数是constexpr构造函数。 - 此构造函数仅在满足以下条件时参与重载决议:
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>是false。
辅助变量模板 converts_from_any_cvref 等价于:
template< class T, class W >
constexpr bool converts_from_any_cvref =
std::disjunction_v<std::is_constructible<T, W&>, std::is_convertible<W&, T>,
std::is_constructible<T, W>, std::is_convertible<W, T>,
std::is_constructible<T, const W&>, std::is_convertible<const W&, T>,
std::is_constructible<T, const W>, std::is_convertible<const W, T>>;
参数
| other | - |
另一个
optional
对象,其包含的值将被复制
|
| value | - | 用于初始化所包含值的值 |
| args... | - | 用于初始化所包含值的参数 |
| ilist | - | 用于初始化所包含值的初始化列表 |
异常
T
的构造函数抛出的任何异常。
T
的构造函数抛出的任何异常。具有以下
T
的构造函数抛出的任何异常。
注释
在
LWG 问题 3836
解决之前,从
std::
optional
<
U
>
构造
std::
optional
<
bool
>
时,若
U
不是
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); // 正确:包含值0(从false初始化) std::optional<bool> from_int(op_zero); // 缺陷(LWG 3836):包含true,因为 // op_zero包含有效值,即使从该值 // 初始化bool类型会得到false
| 功能测试 宏 | 值 | 标准 | 功能特性 |
|---|---|---|---|
__cpp_lib_optional
|
202106L
|
(C++20)
(DR20) |
完全 constexpr 化 ( 5,6 ) |
示例
#include <iostream> #include <optional> #include <string> int main() { std::optional<int> o1, // 空值 o2 = 1, // 从右值初始化 o3 = o2; // 拷贝构造函数 // 调用 std::string( initializer_list<CharT> ) 构造函数 std::optional<std::string> o4(std::in_place, {'a', 'b', 'c'}); // 调用 std::string( size_type count, CharT ch ) 构造函数 std::optional<std::string> o5(std::in_place, 3, 'A'); // 使用推导指南从 std::string 移动构造 std::optional o6(std::string{"deduction"}); std::cout << *o2 << ' ' << *o3 << ' ' << *o4 << ' ' << *o5 << ' ' << *o6 << '\n'; }
输出:
1 1 abc AAA deduction
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 应用于 | 发布时的行为 | 正确行为 |
|---|---|---|---|
| LWG 3836 | C++17 |
当从
std::
optional
<
U
>
构造
std::
optional
<
bool
>
时,
若
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
对象
(函数模板) |