Почему спецификация noexcept `operator=(T&& t)` `std: variable` не зависит от спецификации noexcept деструктора внутренних типов?

Длинное название: почему std:variant"s 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

Это не кажется правильным. Я что-то пропустил?

1 ответ

Как правило, стандартные типы библиотек не относятся к типам, имеющим деструкторы броска. Или, в частности, когда деструктор фактически выдает исключение. Об этом есть общее правило ( [res.on.functions])

В некоторых случаях (функции замены, функции-обработчики, операции над типами, используемыми для создания экземпляров стандартных шаблонных компонентов библиотеки) стандартная библиотека C ++ зависит от компонентов, предоставляемых программой C ++. Если эти компоненты не соответствуют их требованиям, этот международный стандарт не устанавливает требований к реализации.

В частности, эффекты не определены в следующих случаях:

...

  • если какая-либо замещающая функция или функция-обработчик или операция деструктора завершается через исключение, если это специально не разрешено в соответствующем Обязательном поведении: параграф.

поскольку variant::operator= не имеет специального утверждения о метании деструкторов, если эти деструкторы действительно выбрасывают - это UB.

Другие вопросы по тегам