Upload
young-ha-kim
View
62
Download
3
Embed Size (px)
Citation preview
Summary of Effective Modern C++
Items 1 & 2
(Homework Assignment – YoungHa Kim)
Item 1Template 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 Refer-ence • 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 overloadvoid 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, ig-
nore 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 intfunc(cx); // T and param are both intfunc(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 2Understand 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 autovoid 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 autovoid 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 typeauto 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 speci-
fication in a C++ 14 lambdastd::vector<int> v;auto resetV = [&v](const auto& newValue) { v = newValue; };resetV( {1,2,3} ); // error! can’t deduce type for {1,2,3}