为什么`std::variant`的`operator=(&t)`的noexcept规范不随内部类型而变?
- 内容介绍
- 文章标签
- 相关推荐
本文共计771个文字,预计阅读时间需要4分钟。
:为什么std::variant的operator+(T t)的noexcept规范不依赖于内部类型的析构函数的noexcept规范?
内容:在cppreference上,可以看到如下模板类定义:
cpptemplate struct variant { variant(T t) noexcept(/* see below */)=default; variant(const variant&) noexcept(/* see below */)=default; variant(variant&&) noexcept(/* see below */)=default; variant& operator=(const variant&) noexcept(/* see below */)=default; variant& operator=(variant&&) noexcept(/* see below */)=default; template variant(variant v) noexcept(/* see below */)=default; template variant& operator=(variant&& v) noexcept(/* see below */)=default; operator T() const noexcept(/* see below */) &; operator T() const noexcept(/* see below */) const &; operator T() const noexcept(/* see below */) &&; operator T() const noexcept(/* see below */) const &&; T value() const noexcept(/* see below */) &; T value() const noexcept(/* see below */) const &; T value() const noexcept(/* see below */) &&; T value() const noexcept(/* see below */) const &&; operator bool() const noexcept(/* see below */) &; operator bool() const noexcept(/* see below */) const &; operator bool() const noexcept(/* see below */) &&; operator bool() const noexcept(/* see below */) const &&; template U value() const noexcept(/* see below */) &; template U value() const noexcept(/* see below */) const &; template U value() const noexcept(/* see below */) &&; template U value() const noexcept(/* see below */) const &&; template U& value() const noexcept(/* see below */) &; template U& value() const noexcept(/* see below */) const &; template U& value() const noexcept(/* see below */) &&; template U& value() const noexcept(/* see below */) const &&; void reset() noexcept(/* see below */) &; void reset() noexcept(/* see below */) const &; void reset(T t) noexcept(/* see below */) &; void reset(T t) noexcept(/* see below */) const &; void reset(variant t) noexcept(/* see below */) &; void reset(variant t) noexcept(/* see below */) const &; void reset(variant&& t) noexcept(/* see below */) &; void reset(variant&& t) noexcept(/* see below */) const &; void reset(variant& t) noexcept(/* see below */) &; void reset(variant& t) noexcept(/* see below */) const &; void reset(variant&& t) noexcept(/* see below */) &; void reset(variant&& t) noexcept(/* see below */) const &; template void reset(variant& t) noexcept(/* see below */) &; template void reset(variant& t) noexcept(/* see below */) const &; template void reset(variant&& t) noexcept(/* see below */) &; template void reset(variant&& t) noexcept(/* see below */) const &; template void reset(U t) noexcept(/* see below */) &; template void reset(U t) noexcept(/* see below */) const &; template void reset(variant& t) noexcept(/* see below */) &; template void reset(variant& t) noexcept(/* see below */) const &; template void reset(variant&& t) noexcept(/* see below */) &; template void reset(variant&& t) noexcept(/* see below */) const &; void swap(variant& other) noexcept(/* see below */) &; void swap(variant& other) noexcept(/* see below */) const &;};
其中,`operator+(T t)`的noexcept规范不依赖于内部类型的析构函数的noexcept规范。这是因为`operator+`操作符的noexcept规范只与操作符本身有关,而与内部类型的析构函数的noexcept规范无关。
长标题:为什么std:variant的operator =(T& t)的noexcept规范不依赖于内部类型的析构函数的noexcept规范?我可以在cppreference上看到
template <class T> variant& operator=(T&& t) noexcept(/* see below */);
是
noexcept(std::is_nothrow_assignable_v<T_j&, T> && std::is_nothrow_constructible_v<T_j, T>)
所以这个编译:
struct FooThrow { ~FooThrow() noexcept(false) {throw;} }; static_assert(std::is_nothrow_assignable_v<std::variant<FooThrow, int>, int>);
但是它调用了FooThrow的析构函数,它是noexcept(false):
std::variant<FooThrow, int> x; x = 3; // throws
这似乎不对.我错过了什么吗?
通常,标准库类型不适用于具有抛出析构函数的类型.或者特别是,当析构函数实际发出异常时.关于它的一般规则( [res.on.functions])In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C ++ standard library depends on components supplied by a C ++ program. If these components do not meet their requirements, this International Standard places no requirements on the implementation.
In particular, the effects are undefined in the following cases:
…
- if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.
由于variant :: operator =没有关于抛出析构函数的特殊声明,因此实际抛出这些析构函数是UB.
本文共计771个文字,预计阅读时间需要4分钟。
:为什么std::variant的operator+(T t)的noexcept规范不依赖于内部类型的析构函数的noexcept规范?
内容:在cppreference上,可以看到如下模板类定义:
cpptemplate struct variant { variant(T t) noexcept(/* see below */)=default; variant(const variant&) noexcept(/* see below */)=default; variant(variant&&) noexcept(/* see below */)=default; variant& operator=(const variant&) noexcept(/* see below */)=default; variant& operator=(variant&&) noexcept(/* see below */)=default; template variant(variant v) noexcept(/* see below */)=default; template variant& operator=(variant&& v) noexcept(/* see below */)=default; operator T() const noexcept(/* see below */) &; operator T() const noexcept(/* see below */) const &; operator T() const noexcept(/* see below */) &&; operator T() const noexcept(/* see below */) const &&; T value() const noexcept(/* see below */) &; T value() const noexcept(/* see below */) const &; T value() const noexcept(/* see below */) &&; T value() const noexcept(/* see below */) const &&; operator bool() const noexcept(/* see below */) &; operator bool() const noexcept(/* see below */) const &; operator bool() const noexcept(/* see below */) &&; operator bool() const noexcept(/* see below */) const &&; template U value() const noexcept(/* see below */) &; template U value() const noexcept(/* see below */) const &; template U value() const noexcept(/* see below */) &&; template U value() const noexcept(/* see below */) const &&; template U& value() const noexcept(/* see below */) &; template U& value() const noexcept(/* see below */) const &; template U& value() const noexcept(/* see below */) &&; template U& value() const noexcept(/* see below */) const &&; void reset() noexcept(/* see below */) &; void reset() noexcept(/* see below */) const &; void reset(T t) noexcept(/* see below */) &; void reset(T t) noexcept(/* see below */) const &; void reset(variant t) noexcept(/* see below */) &; void reset(variant t) noexcept(/* see below */) const &; void reset(variant&& t) noexcept(/* see below */) &; void reset(variant&& t) noexcept(/* see below */) const &; void reset(variant& t) noexcept(/* see below */) &; void reset(variant& t) noexcept(/* see below */) const &; void reset(variant&& t) noexcept(/* see below */) &; void reset(variant&& t) noexcept(/* see below */) const &; template void reset(variant& t) noexcept(/* see below */) &; template void reset(variant& t) noexcept(/* see below */) const &; template void reset(variant&& t) noexcept(/* see below */) &; template void reset(variant&& t) noexcept(/* see below */) const &; template void reset(U t) noexcept(/* see below */) &; template void reset(U t) noexcept(/* see below */) const &; template void reset(variant& t) noexcept(/* see below */) &; template void reset(variant& t) noexcept(/* see below */) const &; template void reset(variant&& t) noexcept(/* see below */) &; template void reset(variant&& t) noexcept(/* see below */) const &; void swap(variant& other) noexcept(/* see below */) &; void swap(variant& other) noexcept(/* see below */) const &;};
其中,`operator+(T t)`的noexcept规范不依赖于内部类型的析构函数的noexcept规范。这是因为`operator+`操作符的noexcept规范只与操作符本身有关,而与内部类型的析构函数的noexcept规范无关。
长标题:为什么std:variant的operator =(T& t)的noexcept规范不依赖于内部类型的析构函数的noexcept规范?我可以在cppreference上看到
template <class T> variant& operator=(T&& t) noexcept(/* see below */);
是
noexcept(std::is_nothrow_assignable_v<T_j&, T> && std::is_nothrow_constructible_v<T_j, T>)
所以这个编译:
struct FooThrow { ~FooThrow() noexcept(false) {throw;} }; static_assert(std::is_nothrow_assignable_v<std::variant<FooThrow, int>, int>);
但是它调用了FooThrow的析构函数,它是noexcept(false):
std::variant<FooThrow, int> x; x = 3; // throws
这似乎不对.我错过了什么吗?
通常,标准库类型不适用于具有抛出析构函数的类型.或者特别是,当析构函数实际发出异常时.关于它的一般规则( [res.on.functions])In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C ++ standard library depends on components supplied by a C ++ program. If these components do not meet their requirements, this International Standard places no requirements on the implementation.
In particular, the effects are undefined in the following cases:
…
- if any replacement function or handler function or destructor operation exits via an exception, unless specifically allowed in the applicable Required behavior: paragraph.
由于variant :: operator =没有关于抛出析构函数的特殊声明,因此实际抛出这些析构函数是UB.

