Ниже приведен код, демонстрирующий вопрос:
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_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 Это так. Здесь ничего не сломано, так работает С++. Я допускаю, что категории значений могут сбивать с толку, потому что они «невидимы». Я бы предпочел увидеть IDE, которая может показывать вам категорию значения некоторого выражения при наведении курсора мыши, но я не думаю, что такая вещь еще существует.
ref в моем примере, имеет тип T, а не тип T&&. Вот как это работает. С перегрузкой проблем нет, только с пониманием выражений.
Это вполне разумное поведение — ссылка на 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
}
Ссылки Rvalue считаются lvalue. Вам нужно
std::moveссылку.