is_assignable и std :: unique_ptr - PullRequest
       20

is_assignable и std :: unique_ptr

0 голосов
/ 21 декабря 2018

Здесь - это тестовый файл из 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 предоставляет назначения перемещения?

1 Ответ

0 голосов
/ 21 декабря 2018

p1 и p2 относятся к другому типу.В отличие от shared_ptr, удалитель unique_ptr является частью типа указателя.Это означает, что оператор присваивания перемещения не позволяет назначать (даже перемещать-присваивать) между двумя unique_ptr с, если их типы удаления отличаются.

unique_ptr также предлагает шаблон оператора присваивания, который позволяет назначать изЗначение unique_ptr для другого удалителя, но удаляемые должны быть назначены (см. ссылка ).Таким образом, вы можете запустить статический огонь по утверждению, назначив удаляющим:

struct do_nothing
{
    template <class T>
    void operator()(T*) {}

    template <class T>
    operator std::default_delete<T>() { return {}; }
};

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.    
}

[Пример в реальном времени]

...