Download as pdf or txt
Download as pdf or txt
You are on page 1of 26

Summary of Effective

Modern C++
Items 1 & 2

(Homework Assignment – YoungHa Kim)


Item 1
Template Type Deduction
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.
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);


Int, Const int, Const int&
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)
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&
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*
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&&)
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.
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.
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&&
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.
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.


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.
Passing Array Arguments
const char name[] = “YH Kim”; // char[7]
const char *ptrName = name; // array decays to ptr

template<typename T>
void func(T param);

func(name); // what happens??


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*
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]
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)
Item 2
Understand auto type deduction
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


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


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.
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


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>
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}

You might also like