0% found this document useful (0 votes)
35 views

Summary of Effective Modern C++: Items 1 & 2

Template type deduction determines the types of template parameters based on the types of function arguments. There are three main cases: 1) Parameters are references/pointers - template type matches argument type ignoring references/pointers. 2) Parameters are universal references - template type matches argument type as lvalue or rvalue reference depending on argument. 3) Parameters are value types - template type matches underlying type of argument ignoring top-level references/const/volatile. Auto type deduction works similarly to template type deduction except initializer lists always deduce to std::initializer_list instead of underlying type.

Uploaded by

Tamás Benyács
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
35 views

Summary of Effective Modern C++: Items 1 & 2

Template type deduction determines the types of template parameters based on the types of function arguments. There are three main cases: 1) Parameters are references/pointers - template type matches argument type ignoring references/pointers. 2) Parameters are universal references - template type matches argument type as lvalue or rvalue reference depending on argument. 3) Parameters are value types - template type matches underlying type of argument ignoring top-level references/const/volatile. Auto type deduction works similarly to template type deduction except initializer lists always deduce to std::initializer_list instead of underlying type.

Uploaded by

Tamás Benyács
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 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