7

I am trying to understand how lvalues bind to rvalue references. Consider this code:

#include <iostream> template<typename T> void f(T&& x) { std::cout << x; } void g(int&& x) { std::cout << x; } int main() { int x = 4; f(x); g(x); return 0; } 

While the call to f() is fine, the call to g() gives a compile-time error. Does this kind of binding work only for templates? Why? Can we somehow do it without templates?

2 Answers 2

7

Since T is a template argument, T&& becomes a forwarding-reference. Due to reference collapsing rules, f(T& &&) becomes f(T&) for lvalues and f(T &&) becomes f(T&&) for rvalues.

Sign up to request clarification or add additional context in comments.

5 Comments

That makes sense. But suppose I don't need templates, then is there any way to get universal references, say in the example above? I edited the question slightly for this.
@r.v You can provide a second overload of g for lvalues (void g(int&)), or you can move the lvalues with std::move.
Yes, these are possible solutions but I was hoping we get something in line of a universal reference: given a type T (fixed, not templated), I can match both T& and T&& in one call (no overloads) and then use forwarding, etc. That definitely helps to reduce some redundant code.
@r.v Sorry, but excluding what I have suggested this is impossible to do without templates. :( Perfect forwarding works great with templates by the way.
No problem, thanks. I think we have a legitimate use case here though.
1

0x499602D2 has already answered your question; nevertheless, the following changes to your code might give further insights.

I have added a static_assert to f to check the deduced type:

#include <type_traits> template<typename T> void f(T&& x) { static_assert(std::is_same<T&&, int&>::value,""); std::cout << x; } 

The assert does not fail, so the type of x in f is eventually int& (in this particular example).

I have changed how g is called in main:

g(std::move(x)); 

Now the code compiles and the program works as expected and prints 44.

Hope this helps a bit in understanding rvalue references.

1 Comment

There's already a template for that: std::is_rvalue_reference

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.