std::expected<T,E>::operator=
来自cppreference.com
| 主模板 |
||
| (1) | (C++23 起) | |
| (2) | (C++23 起) | |
| (3) | (C++23 起) | |
| (4) | (C++23 起) | |
| (5) | (C++23 起) | |
void 部分特化 |
||
| (6) | (C++23 起) | |
| (7) | (C++23 起) | |
| (8) | (C++23 起) | |
| (9) | (C++23 起) | |
| 辅助函数模板 |
||
| |
(10) | (C++23 起) (仅用于阐述*) |
为一个现存的 expected 对象赋予新值。
参数
| other | - | 包含值要用来赋值的 expected 对象
|
| v | - | 用来初始化包含值的值 |
| e | - | 包含值要用来赋值的 std::unexpected 对象 |
| newval | - | 要构造的包含值 |
| oldval | - | 要销毁的包含值 |
| args | - | 用作 newval 的初始化器的实参
|
效果
主模板赋值运算符
1,2) 将
other 的状态赋给 *this。 如果
has_value() 与 rhs.has_value() 的值不同(即 *this 和 other 之一包含预期值 val,而另一个对象包含非预期值 unex),那么就会调用仅用于阐述的辅助函数模板 reinit-expected 来安全地更新状态。1) 按以下方式对包含值进行赋值:
has_value() 的值
|
other.has_value() 的值
| |
|---|---|---|
true
|
false
| |
true
|
val = *other;
|
reinit-expected (unex, val, other.error());
|
false
|
reinit-expected (val, unex, *other);
|
unex = other.error();
|
2) 按以下方式对包含值进行赋值:
has_value() 的值
|
other.has_value() 的值
| |
|---|---|---|
true
|
false
| |
true
|
val = std::move(*other);
|
reinit-expected (unex, val, std::move(other.error()));
|
false
|
reinit-expected (val, unex, std::move(*other));
|
unex = std::move(other.error());
|
然后,如果没有抛出异常,那么就会执行
has_val = other.has_value();.3) 按以下方式对预期值进行赋值:
has_value() 的值
|
等价于 |
|---|---|
true
|
val = std::forward<U>(v);
|
false
|
reinit-expected(val, unex, std::forward<U>(v));has_val = false;
|
4,5) 按以下方式对非预期值进行赋值:
| 重载 | has_value() 的值
|
等价于 |
|---|---|---|
| (4) | true
|
reinit-expected(val, unex, std::forward<const G&>(e.error()));has_val = false;
|
false
|
unex = std::forward<const G&>(e.error());
| |
| (5) | true
|
reinit-expected(val, unex, std::forward<G>(e.error()));has_val = false;
|
false
|
unex = std::forward<G>(e.error());
|
void 部分特化赋值运算符
6) 按以下方式对非预期值进行赋值或销毁:
has_value() 的值
|
other.has_value() 的值
| |
|---|---|---|
true
|
false
| |
true
|
(没有效果) | std::construct_at (std::addressof(unex), rhs.unex);has_val = false;
|
false
|
std::destroy_at (std::addressof(unex));has_val = true;
|
unex = other.error();
|
7) 按以下方式对非预期值进行赋值或销毁:
has_value() 的值
|
other.has_value() 的值
| |
|---|---|---|
true
|
false
| |
true
|
(没有效果) | std::construct_at (std::addressof(unex), std::move(rhs.unex));has_val = false;
|
false
|
std::destroy_at(std::addressof(unex));has_val = true;
|
unex = std::move(other.error());
|
8,9) 按以下方式对非预期值进行赋值:
| 重载 | has_value() 的值
|
等价于 |
|---|---|---|
| (8) | true
|
std::construct_at(std::addressof(unex), std::forward<const G&>(e.error()));has_val = false;
|
false
|
unex = std::forward<const G&>(e.error());
| |
| (9) | true
|
std::construct_at(std::addressof(unex), std::forward<G>(e.error()));has_val = false;
|
false
|
unex = std::forward<G>(e.error());
|
辅助函数模板
仅用于阐述的函数模板 reinit-expected “定义”如下:
template<class NewType, class OldType, class... Args>
constexpr void reinit-expected(NewType& new_val, OldType& old_val, Args&&... args)
{
// 情况 1:“new_val” 的构造不会抛出:
// 在销毁 “old_val” 后可以直接构造 “new_val”
if constexpr (std::is_nothrow_constructible_v<NewType, Args...>)
{
std::destroy_at(std::addressof(old_val));
std::construct_at(std::addressof(new_val), std::forward<Args>(args)...);
}
// 情况 2:“new_val” 的移动构造不会抛出:
// 先构造一个临时的 NewType 对象
// (如果该构造抛出异常,那么 “old_val” 不会受到影响)
else if constexpr (std::is_nothrow_move_constructible_v<NewType>)
{
NewType temp(std::forward<Args>(args)...); // 可能会抛出异常
std::destroy_at(std::addressof(old_val));
std::construct_at(std::addressof(new_val), std::move(temp));
}
// 情况 3:“new_val” 的构造可能会抛出:
// 需要备份 “old_val” 以从异常中恢复
else
{
OldType temp(std::move(old_val)); // 可能会抛出异常
std::destroy_at(std::addressof(old_val));
try
{
std::construct_at(std::addressof(new_val),
std::forward<Args>(args)...); // 可能会抛出异常
}
catch (...)
{
std::construct_at(std::addressof(old_val), std::move(temp));
throw;
}
}
}当赋值会导致 *this 持有另一个预期种类的值时(即从持有预期值到持有非预期值,或从持有非预期值到持有预期值)时就会调用此函数模板。
此时在构造新值 newval 前需要先销毁旧值 oldval。然而构造 newval 可能会抛出异常。为提供强异常安全保证,在重抛异常前需要恢复旧值,这样在处理异常时 *this 就会具有有效状态。
返回值
1-9)
*this约束和补充信息
主模板赋值运算符
1) 此重载被定义为弃置,除非以下所有值都是
true:
std::is_copy_assignable_v<T>std::is_copy_constructible_v<T>std::is_copy_assignable_v<E>std::is_copy_constructible_v<E>std::is_nothrow_move_constructible_v<T> || std::is_nothrow_move_constructible_v<E>
2) 此重载只有在以下所有值都是
true 时才会参与重载决议:
std::is_move_assignable_v<T>std::is_move_constructible_v<T>std::is_move_assignable_v<E>std::is_move_constructible_v<E>std::is_nothrow_move_constructible_v<T> || std::is_nothrow_move_constructible_v<E>
3) 此重载只有在满足以下所有条件时才会参与重载决议:
std::is_same_v<expected, std::remove_cvref_t<U>>isfalse.std::remove_cvref_t<U>is not a specialization ofstd::unexpected.- All following values are
true:std::is_constructible_v<T, U>std::is_assignable_v<T&, U>std::is_nothrow_constructible_v<T, U> || std::is_nothrow_move_constructible_v<T> ||std::is_nothrow_move_constructible_v<E>
4) 此重载只有在以下所有值都是
true 时才会参与重载决议:
std::is_constructible_v<E, const G&>std::is_assignable_v<E&, const G&>std::is_nothrow_constructible_v<E, const G&> || std::is_nothrow_move_constructible_v<T> ||std::is_nothrow_move_constructible_v<E>
5) 此重载只有在以下所有值都是
true 时才会参与重载决议:
std::is_constructible_v<E, G>std::is_assignable_v<E&, G>std::is_nothrow_constructible_v<E, G> || std::is_nothrow_move_constructible_v<T> ||std::is_nothrow_move_constructible_v<E>
void 部分特化赋值运算符
6) 此重载被定义为弃置,除非
std::is_copy_assignable_v<E> 和 std::is_copy_constructible_v<E> 都是 true。7) 此重载只有在
std::is_move_constructible_v<E> 和 std::is_move_assignable_v<E> 都是 true 时才会参与重载决议。8) 此重载只有在
std::is_constructible_v<E, const G&> 和 std::is_assignable_v<E&, const G&> 都是 true 时才会参与重载决议。9) 此重载只有在
std::is_constructible_v<E, G> 和 std::is_assignable_v<E&, G> 都是 true 时才会参与重载决议。异常
2)
noexcept 说明:
noexcept( std::is_nothrow_move_constructible_v<T> && std::is_nothrow_move_assignable_v<T> && std::is_nothrow_move_constructible_v<E> && std::is_nothrow_move_assignable_v<E>)7)
noexcept 说明:
noexcept(std::is_nothrow_move_constructible_v<E> && std::is_nothrow_move_assignable_v<E>)示例
| 本节未完成 原因:暂无示例 |
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
| 缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
|---|---|---|---|
| LWG 3886 | C++23 | 重载 (3) 的默认模板实参是 T
|
改成 std::remove_cv_t<T>
|
| LWG 4025 | C++23 | 在 E 不可移动构造或移动赋值时重载 (7) 会被定义为弃置
|
此时该重载不会参与重载决议 |
参阅
| 原位构造预期值 (公开成员函数) |