Перегрузка для rvalue?

Ниже приведен код, демонстрирующий вопрос:

class X {};
X x;
X&& rvalue_ref = std::move(x);
static_assert(std::is_same<decltype(rvalue_ref), X&&>::value, "Different types"); //To be sure that type is X&&
void func(X&) {
    cout << "lvalue reference";
}

void func(X&&) {
    cout << "rvalue reference";
}
int main() {
    func(rvalue_ref);
}

Выход:

lvalue reference

Не могли бы вы объяснить причину этого? У нас есть переменная типа X&& и перегрузка для этого типа, но эта перегрузка не вызывается.

Ссылки Rvalue считаются lvalue. Вам нужно std::move ссылку.

HolyBlackCat 24.05.2019 12:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ссылки на самом деле так не работают. Ваш аргумент rvalue_ref, несмотря на его тип, является lvalue выражение. Вам нужно будет сделать std::move снова, чтобы сделать его rvalue.

Типы и категории значений — это две разные вещи, и может быть трудно помнить, что выражение, именующее типизированный объект ссылка на rvalue, не является автоматически выражением rvalue.

Учитывайте также:

void foo(T&& ref)
{
   bar(ref);             // lvalue arg
   bar(std::move(ref));  // rvalue arg
}

Это также упоминается в Статья cppreference.com "Категории ценности":

Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression

Но не нарушает ли это каких-либо правил разрешения перегрузок функций? Странно, что функция func(T) не вызывается для переменной типа T.

beginpluses 24.05.2019 12:38

@beginpluses Это так. Здесь ничего не сломано, так работает С++. Я допускаю, что категории значений могут сбивать с толку, потому что они «невидимы». Я бы предпочел увидеть IDE, которая может показывать вам категорию значения некоторого выражения при наведении курсора мыши, но я не думаю, что такая вещь еще существует.

Lightness Races in Orbit 24.05.2019 12:52
"для переменной типа T" Вы должны забыть о переменных и думать о выражения. Выражение, которое вы передаете ref в моем примере, имеет тип T, а не тип T&&. Вот как это работает. С перегрузкой проблем нет, только с пониманием выражений.
Lightness Races in Orbit 24.05.2019 13:28

Это вполне разумное поведение — ссылка на rvalue — это lvalue в C++. Что означает получить вывод

rvalue reference

вы должны использовать std::move вот так:

int main() {
    func(std::move(rvalue_ref));
}

Это может быть особенно запутанным при передаче параметров функциям. Например, чтобы передать аргумент как rvalue, вы должны использовать std::move:

void foo(bar &&baz) {
    function_taking_rvalue_reference(std::move(baz));// <--- this move is necessary
}

Другие вопросы по теме