Неподвижный уникальный указатель С++ 17

Я наткнулся на этот ответ " Запретить перемещение unique_ptr С++ 11". Тем не менее, при тестировании его на компиляторе в сети, это работает с С++ 11 (ошибка компилятора std::move), но с С++ 17, я вижу, что std::move ниже успешно. Разве компилятор не должен выдавать ошибку в этой строке? Также, если некоторая семантика изменилась в С++ 17, каков правильный способ создания неизменяемого unique_ptr в С++ 17 и далее.

template <typename T>
using scoped_ptr = const std::unique_ptr<T>;

int main()
{
    auto p = scoped_ptr<int>(new int(5));
    auto p2 = std::move(p); // should be error?
    std::cout << *p2 << std::endl; // 5
    return 0;
}

Вы можете попробовать это онлайн здесь.

Ответ 1

p не const. Смотрите здесь, чтобы это провалилось так, как вы ожидаете.

auto выводит как template<class T>void foo(T). T никогда не выводится как const, как и auto p=.

Между тем, auto p = строка auto p = работает, потому что вы скомпилировали ее в режиме . В он не компилируется. Это потому, что как значения отличаются в 17; некоторые называют разницу гарантированной.

Если вы хотите неподвижный уникальный ptr:

template<class T, class D>
struct immobile_ptr:private std::unique_ptr<T, D>{
  using unique_ptr<T>::operator*;
  using unique_ptr<T>::operator->;
  using unique_ptr<T>::get;
  using unique_ptr<T>::operator bool;
  // etc

  // manually forward some ctors, as using grabs some move ctors in this case
};
template<class T, class...Args>
immobile_ptr<T> make_immobile_ptr(Args&&...args); // todo

альтернатива может заключаться в том, чтобы взять уникальный ptr с неподвижным разрушителем.

template<class X>
struct nomove_destroy:std::destroy<T>{
  nomove_destroy(nomove_destroy&&)=delete;
  nomove_destroy()=default;
  nomove_destroy& operator=(nomove_destroy&&)=delete;
};
template<class T>
using nomove_ptr=std::unique_ptr<T,nomove_destroy<T>>;

Но я не уверен, что это сработает.

Ответ 2

Следует отметить, что p объявлен как нереференсного типа, const часть аргумента scoped_ptr<int>(new int(5)) игнорируются в типе выводе. Тогда результатом вывода типа для p будет std::unique_ptr<int>, а не const std::unique_ptr<int> (т. scoped_ptr<int> как вы и ожидали).

То, что вы хотите, может быть

auto& p = scoped_ptr<int>(new int(5)); // p is of type const std::unique_ptr<int>& now

Ответ 3

Добро пожаловать в мир дедукции типов в C++. Пытаться

auto & p = scoped_ptr<int>(new int(5));

или же

auto && p = scoped_ptr<int>(new int(5));

вместо. Эта лекция может быть полезна: https://www.youtube.com/watch?v=wQxj20X-tIU