Думаю, нет, но хочу подтвердить. Есть ли смысл const Foo&&
, где Foo
тип класса?
c++
c++11
constants
rvalue-reference
fredoverflow
источник
источник
const&&
они очень важны, хотя он не говорит почему: youtube.com/watch?v=JhgWFYfdIho#t=54m20sОтветы:
Иногда они полезны. Сам черновик C ++ 0x использует их в нескольких местах, например:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
Выше двух перегрузок гарантировать , что другие
ref(T&)
иcref(const T&)
функцию не связываются с rvalues (что было бы возможно).Обновить
Я только что проверил официальный стандарт N3290 , который, к сожалению, не является общедоступным, и он имеет в 20.8 объектах функций [function.objects] / p2:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
Затем я проверил самый последний проект, опубликованный после C ++ 11, который является общедоступным, N3485 , и в 20.8 Function objects [function.objects] / p2 он все еще говорит:
template <class T> void ref(const T&&) = delete; template <class T> void cref(const T&&) = delete;
источник
const T&&
используются?const T&&
предотвращает глупое использование явных аргументов шаблона формыref<const A&>(...)
. Это не очень веский аргумент, но ценаconst T&&
заT&&
него минимальна.Семантика получения ссылки на const rvalue (а не for
=delete
) заключается в том, чтобы сказать:Следующий вариант использования мог бы быть IMHO хорошим вариантом использования для ссылки rvalue на const , хотя язык решил не использовать этот подход (см. Исходное сообщение SO ).
Случай: конструктор интеллектуальных указателей из необработанного указателя
Обычно рекомендуется использовать
make_unique
иmake_shared
, но обаunique_ptr
иshared_ptr
могут быть построены из необработанного указателя. Оба конструктора получают указатель по значению и копируют его. Оба позволяют (т.е. в смысле: не предотвращать ) непрерывное использование исходного указателя, переданного им в конструкторе.Следующий код компилируется и дает двойное освобождение :
int* ptr = new int(9); std::unique_ptr<int> p { ptr }; // we forgot that ptr is already being managed delete ptr;
Оба
unique_ptr
иshared_ptr
могут предотвратить вышеуказанное, если их соответствующие конструкторы ожидают получить необработанный указатель как const rvalue , например, дляunique_ptr
:unique_ptr(T* const&& p) : ptr{p} {}
В этом случае приведенный выше двойной бесплатный код не будет компилироваться, но будет следующее:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
Обратите внимание, что его
ptr
можно было использовать после перемещения, поэтому потенциальная ошибка не исчезла полностью. Но если от пользователя требуется вызватьstd::move
такую ошибку, это попадет под общее правило: не используйте перемещенный ресурс.Можно спросить: хорошо, а почему именно
T*
const&& p
?Причина проста - разрешить создание
unique_ptr
из константного указателя . Помните, что ссылка const rvalue является более общей, чем просто ссылка rvalue, поскольку она принимает какconst
иnon-const
. Таким образом, мы можем допустить следующее:int* const ptr = new int(9); auto p = std::unique_ptr<int> { std::move(ptr) };
это не пошло бы, если бы мы ожидали только ссылку rvalue (ошибка компиляции: невозможно привязать const rvalue к rvalue ).
Во всяком случае, предлагать такое уже поздно. Но эта идея представляет собой разумное использование ссылки rvalue на const .
источник
Они разрешены, и даже функции ранжируются на основе
const
, но поскольку вы не можете перейти от объекта const, на который ссылаетсяconst Foo&&
, они бесполезны.источник
const T&, T&, const T&&, T&&
Помимо std :: ref , стандартная библиотека также использует ссылку на const rvalue в std :: as_const для той же цели.
template <class T> void as_const(const T&&) = delete;
Он также используется как возвращаемое значение в std :: optional при получении обернутого значения:
constexpr const T&& operator*() const&&; constexpr const T&& value() const &&;
Как и в std :: get :
template <class T, class... Types> constexpr const T&& get(const std::variant<Types...>&& v); template< class T, class... Types > constexpr const T&& get(const tuple<Types...>&& t) noexcept;
Предположительно это сделано для того, чтобы поддерживать категорию значения, а также постоянство оболочки при доступе к обернутому значению.
Это имеет значение, могут ли для обернутого объекта вызываться функции с определением const rvalue ref. Тем не менее, я не знаю, как использовать функции с квалификацией const rvalue ref.
источник
Я не могу представить себе ситуацию, когда это было бы полезно напрямую, но это могло бы использоваться косвенно:
template<class T> void f(T const &x) { cout << "lvalue"; } template<class T> void f(T &&x) { cout << "rvalue"; } template<class T> void g(T &x) { f(T()); } template<class T> void h(T const &x) { g(x); }
T в g - это T const, поэтому f x - это T const &&.
Вероятно, это приводит к ошибке компиляции в f (когда он пытается переместить или использовать объект), но f может принимать rvalue-ref, чтобы его нельзя было вызвать для lvalues без изменения rvalue (как в слишком простом пример выше).
источник