3. Lvalue, Rvalue
• Definition
• Lvalue, is a value with a specific location in memory (think of it as a
location value)
• Rvalue is a value that is not an Lvalue.
• Generally, a temporary variable or value.
4. Int, Const int, Const int&
• Let’s execute the following code: (can only modify x,
• otherwise you get a compiler error, cannot modify const)
int x = 27;
const int cx = x;
const int& rx = x;
printf("x=%d, cx=%d, rx=%d n", x, cx, rx);
x = 20;
printf("x=%d, cx=%d, rx=%d n", x, cx, rx);
6. Template Type Deduction
• Let’s refer to the following code example:
• Deduced types will depend on the form of Paramtype and
expr, which can be divided into 3 cases.
Template<typename T>
Void func(Paramtype param);
Func(expr)
7. Case 1: Paramtype is a Reference or
Pointer, but not a Universal Reference
• In this case:
• If expr is a reference, ignore the reference
• Pattern-match expr’s type against Paramtype to determine T
Template<typename T>
Void func(T& param);
Int x = 27; const int CX = x; const int& RX = x;
Func(x); // T is int, paramtype is int&
Func(CX); // T is const int, paramtype is const int&
Func(RX); // T is const int, paramtype is const int&
8. Case 1: Works the same for pointers
• In this case:
Template<typename T>
Void func(T* param);
Int x = 27;
const int* px = &x;
Func(&x); // T is int, paramtype is int*
Func(px); // T is const int, paramtype is const int*
9. Rvalue Reference
• If X is any type, then X&& is called an rvalue reference to X. For
better distinction, the ordinary reference X& is now also called an
lvalue reference.
void foo(X& x); // lvalue reference overload
void foo(X&& x); // rvalue reference overload
X x;
X foobar();
foo(x); // argument is lvalue: calls foo(X&)
foo(foobar()); // argument is rvalue: calls foo(X&&)
10. Universal Reference
• If a variable or parameter is declared to have type T&& for
some deduced type T, that variable or parameter is a
universal reference.
• Things that are declared as rvalue reference can be lvalues or
rvalues. The distinguishing criterion is: if it has a name, then
it is an lvalue. Otherwise, it is an rvalue.
11. Case 2: Paramtype is a Universal
Reference
• Type deduction for universal reference parameters are
different for Lvalues and Rvalues.
• This never happens for non-universal references.
12. Case 2: Paramtype is a Universal
Reference
• If expr is an Lvalue, both T and Paramtype are deduced to be
Lvalue references. (If Rvalue, then case 1 applies)
Template<typename T>
Void func(T&& param);
Int x = 27; const int CX = x; const int& RX = x;
Func(x); // x is Lvalue, so T is int&, paramtype is int&
Func(CX); // CX is Lvalue, so T is const int&, paramtype is const int&
Func(RX); // RX is Lvalue, so T is const int&, paramtype is const int&
Func(27); // 27 is Rvalue, so T is int, paramtype is int&&
13. Case 3: Paramtype is neither a pointer
or reference
• We are dealing with pass by value
• This means param will be a copy of whatever is passed in
• A completely new object
• If expr’s type is a reference, ignore the reference
• If after ignoring reference, expr is const or volatile, ignore
const or volatile.
14. Case 3: Paramtype is neither a pointer
or reference
template<typename T>
void func(T param);
int x = 27; const int cx = x; const int rx = x;
func(x); // T and param are both int
func(cx); // T and param are both int
func(rx); // T and param are both int
• param is not const, because it is a copy of cx or rx.
15. Case 3: Paramtype is neither a pointer
or reference
template<typename T>
void func(T param);
const char* const ptr = “asdf”; // const pointer to a const object
// const pointer can’t point to a different location and cannot be null
func(ptr); // param will be const char*
• constness of ptr is ignored when copied to the new pointer param,
but constness of what ptr points to is preserved.
17. Passing Array Arguments
C++ handles
void myFunc(int param[]);
void myFunc(int* param);
as the same function (almost).
func(name); // array parameters are treated as pointer
parameters, so the value is deduced as a pointer type. In this
case const char*
18. Passing Array Arguments
• functions cannot declare parameters that are arrays, but can
declare parameters that are pointers to arrays.
template<typename T>
void func(T& param);
func(name); // pass array to func
• the type deduced is the actual type of the array.
• so type of func’s parameter is const char(&)[7]
19. Function Arguments
• Functions can also decay into pointers.
template<typename T>
void f1(T param);
template<typename T>
void f2(T& param);
void func(int);
f1(func); // param is deduced as pointer to func, void*(int)
f2(func); // param is deduced as ref to func, void&(int)
21. Auto vs Template Type Deduction
• Basically the same thing
• If we have:
auto x = 2;
• this is handled as:
template<typename T> // conceptual template for deducing auto
void func(T param);
func(2); // param’s type is auto’s type
22. Auto vs Template Type Deduction
• If we have:
const auto& rx = x;
• this is handled as:
template<typename T> // conceptual template for deducing auto
void func(const T& param);
func(x); // param’s type is auto’s type
23. Exceptions
• Auto deduction works the same as template deduction with
the following exceptions
int x1 = 33; -> auto x1 = 33;
int x2(33); -> auto x2(33);
int x3 = {33}; -> auto x3 = {33};
int x4 {33}; -> auto x4{33};
• x1 and x2 declare a variable of type int with value 33
• x3 and x4 declare a var of type std::initializer_list<int> with a
single element having value 33.
24. Using { } initializers for auto
• Using braced initializers for auto always instantiates
std::initializer_list.
auto x = { 1, 2, 3}; // x’s type is std::initializer_list<int>
template<typename T>
void f(T param);
f( {1,2,3} ); // error! can’t deduce type for T
25. Using { } initializers for auto
• Working code
template<typename T>
void f(std::initializer_list<T> param);
f( {1,2,3} );
// T is deduced as int, and param is std::initializer_list<int>
26. C++ 14
• C++ 14 allows auto on function return type
auto createInitList()
{
return { 1,2,3 }; // error! can’t deduce type for {1,2,3}
}
• this use of auto employs template type deduction, so above code
fails.
• the same is true when auto is used in a parameter type specification
in a C++ 14 lambda
std::vector<int> v;
auto resetV = [&v](const auto& newValue) { v = newValue; };
resetV( {1,2,3} ); // error! can’t deduce type for {1,2,3}