progress

I'd rather be anything but ordinary

0%

Effective modern c++ note1

Deducing Types

Item 1:Understand template type deduction

template<typename T>
void f(ParamType param);

f(expr);

there are three cases:

1.ParamType is a pointer or reference type,but not a universal reference.

2.ParamType is a universal reference.

3.ParamType is neither a pointer nor a reference.

Case1.ParamType is a pointer or reference type,but not a universal reference.

in this case,type deduction works likes this:

template<typename T>
void f(T &param);

1.If expr’s type is a reference,ignore the reference part.
2.Then pattern-match expr’s type against ParamType to determine T.

we have these variable declarations.

int x=27;
const int cx=x;
const int &rx=x;
f(x);//T is int,param's type is int&
f(cx);// T is const int,param's type is const int&
f(rx);//T is const int,param's type is const int &

If we change the type of f’s parameter from T& to const T&,the constness of cx and rx continues to be respected.

template<typename T>
void f(const T& param);

int x=27;
const int cx=x;
const int& rx=x;
f(x);//T is int,param's type is const int&
f(cx);//T is int,param's type is const int&
f(rx);//T is int,param's type is const int&

if param were a pointer (or a pointer to const) instead of a reference,things would work essentially the same way.

template<typename T>
void f(T* param);

int x=27;
const int *px=x;

f(&x);//T is int,param's type is int*
f(px);//T is const in,param's type is const int*

Case 2:ParamType is a Universal Reference

  • If expr is an lvalue,both T and paramType are deduced to be lvalue reference.
  • if expr is an rvalue,the “normal” rules apply.

for example:

template<typename T>
void f(T&& param);
f(x);//x is lvalue,so T is int&,param's type also is

f(cx);//T and param's type both are const int&

f(rx);//T and param's type both are const int&

f(27);//27 is rvalue,so T is int,param's type is int&&

Case 3:ParamType is Neither a Pointer nor a Reference

In this case,we’re dealing with pass-by-value.

template<typename T>
void f(T param);
f(x);//T's and param's type are both int
f(cx);//as below
f(rx);//as below

It’s easy to deal with this case,just ignore the reference ,const,volatile part.but we need recognize that const is ignored only for by-value parameters.
for example:

template<typename T>
void f(T param);
const char* const ptr="fun with pointers";//ptr is const pointer to const object
f(ptr);//pass arg of type const type const char* const

as we know,the const to the right of asterisk declares ptr to be const:ptr can’t be be made to point to a different location,nor can’t it be set to null.the const to the left of asterisk says that what ptr points to is const,hence can’t be modified.
so in accord with the type deduction rule for by-value parameters,the constness of ptr will be ignored,the type deduced for param will be cosnt char.

Array Arguments

As we know,array types are different from pointer types,in many contexts,an array decays into a pointer to its first element.
for example:

const char name[]="TestName";//const char[8]
const char* ptrToName=name;//const char *

if we pass an array to a template taking a by-value parameter,array type decays poninter,but if we pass references to arrays,what happens?

template<typename T>
void f(T& param);

f(name);//T's type is const char [8],and param's type is const char(&)[8]

the ablitiy to declare references to arrays enables creation of a template that deduces the number of elements that an aray contains:

template<typename T,std::size_t N>
constexpr std::size_t arraySize(T (&)[N]) noexpect
{
return N;
}