Несмотря на то, что нельзя передавать значения r в функции, принимающие неконстантные ссылки, можно вызывать функции-члены для значений r, но функция-член не знает, как она была вызвана. Если вы вернете ссылку на текущий объект, вы можете преобразовать rvalues в lvalues:
class scratchpad_t
{
// ...
public:
scratchpad_t& self()
{
return *this;
}
};
void foo(scratchpad_t& r)
{
}
int main()
{
foo(scratchpad_t().self());
}
Обратите внимание, что вызов self()
дает выражение lvalue, хотя scratchpad_t
является значением r.
Пожалуйста, исправьте меня, если я ошибаюсь, но ссылочные параметры Rvalue не принимают ссылки lvalue, поэтому их использование потребует добавления перегрузок ко всем потребителям блокнота, что также вызывает сожаление.
Ну, вы могли бы использовать шаблоны ...
template <typename Scratch> void foo(Scratch&& scratchpad)
{
// ...
}
Если вы вызовете foo
с параметром rvalue, Scratch
будет выведен в scratchpad_t
, и, таким образом, Scratch&&
будет scratchpad_t&&
.
И если вы вызовете foo
с параметром lvalue, Scratch
будет выведено в scratchpad_t&
, и из-за правил свертывания ссылок Scratch&&
также будет scratchpad_t&
.
Обратите внимание, что формальный параметр scratchpad
является именем и, следовательно, lvalue, независимо от того, является ли его тип ссылкой lvalue или ссылкой rvalue. Если вы хотите передать scratchpad
другим функциям, вам больше не нужен шаблонный прием для этих функций, просто используйте ссылочный параметр lvalue.
Кстати, вы понимаете, что временный блокнот, связанный с xyz.initialize_computation(scratchpad_t(1, 2, 3));
, будет уничтожен, как только будет initialize_computation
, верно? Хранение ссылки внутри объекта xyz
для последующего пользователя было бы крайне плохой идеей.
self()
не обязательно должен быть методом-членом, это может быть шаблонная функция
Да, это тоже возможно, хотя я бы переименовал его, чтобы прояснить намерение:
template <typename T>
T& as_lvalue(T&& x)
{
return x;
}