Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behavior of C++ template function

Let's say I have this function:

bool f(int&& one, int&& two) { }

If I attempt to call it with this code:

int x = 4;
f(x, 5);

the compiler will complain that it cannot convert x from lvalue reference to rvalue reference, which is correct.

Now if I convert f into a template function like this:

template <class T, class U>
bool f(T&& one, U&& two) { }

then I can call it with an lvalue reference:

int x = 5;
f(x, 5);

Why is it so? Why doesn't the compiler complain in this case?

like image 260
superkinhluan Avatar asked Oct 03 '13 07:10

superkinhluan


3 Answers

Per § 8.3.3 / 6. It's the reference collapsing rule.

template <class T> void func(T&&)  // Accepts rvalue or lvalue
void func(T&&)                     // Accepts rvalue only
void func(T&)                      // Accepts lvalue only

Worth example from standard draft:

int i;
typedef int& LRI;
typedef int&& RRI;

LRI& r1 = i;           // r1 has the type int&
const LRI& r2 = i;     // r2 has the type int&
const LRI&& r3 = i;    // r3 has the type int&

RRI& r4 = i;           // r4 has the type int&
RRI&& r5 = 5;          // r5 has the type int&&

decltype(r2)& r6 = i;  // r6 has the type int&
decltype(r2)&& r7 = i; // r7 has the type int&
like image 147
masoud Avatar answered Oct 17 '22 15:10

masoud


Because there is a template argument deduction, reference collapsing happens. It is what Scott Meyers calls universal references. The U&& will actually become int &. There is a nice article and video about how it works and how it could be used.

like image 36
Juraj Blaho Avatar answered Oct 17 '22 17:10

Juraj Blaho


This happens because of reference collapsing rules added in c++11

A& & becomes A&
A& && becomes A&
A&& & becomes A&
A&& && becomes A&&

In templates these rules are applied but not in a normal function there is no reference collapsing normally in function. There are some other specific situations where reference collapsing will occur like in the presence of auto, decltype or a typedef (that includes using declarations) That explains the results of your compilation. Reference collapsing had to be added in c++11 because otherwise using references like A & & would become errors since you cannot have a reference to a reference.

like image 6
aaronman Avatar answered Oct 17 '22 17:10

aaronman