Здесь - это тестовый файл из gcc, live demo
struct do_nothing
{
template <class T>
void operator()(T*) {}
};
int
main()
{
int i = 0;
std::unique_ptr<int, do_nothing> p1(&i);
std::unique_ptr<int> p2;
static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); // note ! here.
}
std::is_assignable
Если выражение std::declval<T>() = std::declval<U>()
правильно сформировано в неоцененном контексте, значение константы члена равно true.В противном случае значение ложно.Проверки доступа выполняются как будто из контекста, не связанного ни с одним из типов.
std::declval
:
template<class T>
typename std::add_rvalue_reference<T>::type declval() noexcept;
Тип возвращаемого значения T&&
, если T
не является (возможно, cv-квалифицированным) недействительным, и в этом случае тип возвращаемого значения - T.
Давайте рассмотрим MoveAssignOnly
:
struct MoveAssignOnly {
MoveAssignOnly &operator=(MoveAssignOnly &) = delete;
MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
};
int main()
{
static_assert(
not std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value, "");
}
live demo :
error: static_assert failed due to requirement '!std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value'
Да, не удается скомпилировать, поскольку он предоставляет назначение перемещения
Давайте вернемся к тесту gccфайл и std::unique_ptr
.Как мы знаем, std::unique_ptr
также имеет задание на перемещение .
Однако, в отличие от struct MoveAssignOnly
, static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, "");
(более ясно, static_assert(!std::is_assignable<std::unique_ptr<int>, std::unique_ptr<int, do_nothing>>::value, "");
компилируется счастливо.
Я долго боролся с реализацией unique_ptr
в libcxx, но все еще не могу понятьout: как std::unique_ptr
быть нельзя назначить (! is_assignable
), когда std::unique_ptr
предоставляет назначения перемещения?