Здається, ні, але я хотів би підтвердити. Чи є якесь значення для const Foo&&
, де Foo
тип класу?
Здається, ні, але я хотів би підтвердити. Чи є якесь значення для const Foo&&
, де Foo
тип класу?
Відповіді:
Вони час від часу корисні. Проект C ++ 0x сам використовує їх у кількох місцях, наприклад:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
Зазначені дві перевантаження гарантують, що інші ref(T&)
та cref(const T&)
функції не прив’язуються до значень r (що в іншому випадку було б можливим).
Оновлення
Я щойно перевірив офіційний стандарт 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] / 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 (а не для =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 , наприклад для 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*
констирувати&& p
?
Причина проста, дозволити створення unique_ptr
з вказівника const . Пам'ятайте, що посилання на 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, які мають відношення, на обгорнутому об’єкті. Тим не менш, я не знаю жодного використання для кваліфікованих функцій 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 's x є T const &&.
Цілком ймовірно, це призводить до помилки компіляції у f (коли вона намагається перемістити або використати об'єкт), але f може взяти rvalue-ref, щоб його не можна було викликати на lvalues, не змінюючи rvalue (як у занадто простому приклад вище).
const&&
це дуже важливо, хоча він не каже чому: youtube.com/watch?v=JhgWFYfdIho#t=54m20s