Предположим следующий код C ++ 17:
#include <type_traits>
namespace dtl
{
struct One
{
explicit One(int);
~One() = default;
One(const One &) = delete;
auto operator=(const One &) -> One & = delete;
auto operator=(One &&) -> One & = delete;
One(One &&); // Throwable, not default;
int m_int;
};
struct Two
{
explicit Two(int);
~Two() = default;
Two(const Two &) = delete;
auto operator=(const Two &) -> Two & = delete;
auto operator=(Two &&) noexcept -> Two & = delete;
Two(Two &&) noexcept = default;
One m_one;
};
One::One(One &&) { throw 1; }
static_assert(std::is_nothrow_move_constructible_v<Two>);
}
Код в обозревателе компилятора
Здесь мы ясно видим, что конструктор перемещения класса One
не помечен как noexcept. Класс Two
имеет конструктор перемещения по умолчанию, для которого явно запрашивается значение noexcept.
Если мы проверим этот код, он компилируется с магистралью GCC, магистралью Clang, MSVC 19.28 и не работает с MSVC19.24.
Я проверил следующие источники, которые, кажется, говорят мне, что конструктор перемещения Two
необходимо удалить:
- Программа без конструктора noexcept, принятая gcc, отклонено лязгом
- Ошибка компиляции 'noexcept = default'
- Ошибка 35204 - спецификация исключения std :: chrono явно заданного по умолчанию конструктора по умолчанию не соответствует вычисленному
CWG, выпуск 1778, чтобы прочитать (N4296 [ dcl.fct.def.default] / p3):
Если функция, которая явно задана по умолчанию, объявляется со спецификацией исключения, которая несовместима (15.4) со спецификацией исключения в неявном объявлении, то
если функция явно задана по умолчанию при ее первом объявлении, она определяется как удаленная; в противном случае программа имеет неправильный формат.
Основываясь на этой информации, я могу только сделать вывод, что все 3 компилятора ошибаются, рассматривая Two
как no_throw_move_constructible, и конструктор перемещения должен быть неявно удален. Поскольку для всех троих странно игнорировать этот стандарт, я задаюсь вопросом: действительно ли это ошибка компилятора или я что-то упускаю.