Когда вы используете имя ссылки в качестве выражения, это выражение всегда является lvalue. Неважно, является ли это ссылкой на lvalue или ссылкой на rvalue. Также не имеет значения, была ли ссылка инициализирована lvalue или rvalue.
int &&x = 1;
f(x); // Here `x` is lvalue.
То есть в void f(const T &obj) {...}
, obj
всегда является lvalue, независимо от того, что вы передаете в качестве аргумента.
Также обратите внимание, что категория значений определяется во время компиляции. Поскольку f
не является шаблоном, категория значений каждого выражения в нем не может зависеть от передаваемых вами аргументов.
Таким образом:
Если мы передадим rvalue в f
, будет ли ссылочная перегрузка rvalue g
называться
номер
если f
вызвал функцию, которая принимает экземпляр T
по значению, void h(T obj);
и T
имеет конструктор перемещения (т.е. T(T &&);
), будет ли вызываться конструктор перемещения
номер
В заключение, если мы хотим убедиться, что при вызове f
для значения rvalue ссылка rvalue передается вокруг, сохраняя свое значение rvalue "status", должны ли мы обязательно предоставлять перегрузку ссылки rvalue для f
?
Обеспечение перегрузки является одним из вариантов. Обратите внимание, что в этом случае вы должны явно вызвать std::move
в перегрузке rvalue.
Другим вариантом является использование пересылки ссылок , как предлагает Никол Болас:
template <typename T> void f(T &&t)
{
g(std::forward<T>(t));
}
Здесь std::forward
по существу действует как «условный move
». Он перемещается t
, если ему было передано значение rvalue, и ничего не делает иначе.