Ответ 1
Что касается размещения самого static_assert
, то обе версии вашего кода действительны. Таким образом, нет, static_assert
не должно быть вне определения класса. Формально static_assert
- это объявление. Это разрешено везде, где допускаются объявления.
Проблема, с которой вы сталкиваетесь, не имеет ничего общего с static_assert
.
Проблема заключается в том, что выражение, которое вы используете как аргумент вашего static_assert
(std::is_nothrow_move_constructible
), требует, чтобы тип класса был полностью работоспособным. Но внутри определения класса A
тип класса A
еще не завершен, что делает вывод вашего аргумента недействительным. Вот почему ваш static_assert
работает так, как предполагалось, только за пределами определения класса, где A
завершено. Однако это полностью связано с правильным использованием std::is_nothrow_move_constructible
, а не только static_assert
.
Обратите внимание, что внутри класса класса объектов члены видны полностью, как полный тип, даже если функция-член определена внутри определения класса. Используя эту функцию, вы можете переписать свой код как
class A
{
public:
A(A&&) noexcept {
static_assert(std::is_nothrow_move_constructible<A>::value, "ERROR");
}
};
и std::is_nothrow_move_constructible<A>
выдаст правильный результат.