--- tags: CSE --- ```c++= template<typename T> void f(ParamType param); f(expr); ``` based on the <span style="color:red">__expr__</span> and <span style="color:red">__ParamType__</span>, <span style="color:red">__T__</span> will be deduced. ## Case 1: <span style="color:red">*__ParamType__*</span> is a reference or pointer, but not a universal reference then, type deduction works like this: 1. if _expr_'s type is a reference, ignore the reference part. 2. then pattern-match _expr_'s type against _ParamType_ to determine T. (preserve the [CV qualifier](https://en.cppreference.com/w/cpp/language/cv)) example 1: ```cpp= template<typename T> void f(T& param); int x; const int cx; const int& rx; f(x); // T is int, ParamType is int& f(cx); // T is const int, ParamType is const int& f(rx); // T is const int, ParamType is const int& ``` example 2: ```cpp= template<typename T> void f(const T& param); int x; const int cx; const int& rx; f(x); // T is int, ParamType is int& f(cx); // T is int, ParamType is const int& f(rx); // T is int, ParamType is const int& ``` example 3: ```cpp= template<typename T> void f(T* param); int x; const int *px; char name[] = "0123"; f(&x); // T is int, ParamType is int* f(px); // T is const int, ParamType is const int* f(name); // the type of name is char * const. // though the const pointer can't be matched, // the char * const can decay to char * // so, T is char, ParamType is char * ``` we'll talk about what happens when we pass an array later. ## Case 2: <span style="color:red">*__ParamType__*</span> is a universal reference universal reference is like rvalue refernce, but they behave differently, and the invoking place is differently, too. ```cpp= void f(int&& a); // rvalue reference // only take rvalue template<typename T> void g(T&& a); // universal reference // can take rvalue and glvalue auto&& a = Obj(); // universal reference ``` in the case, type deduction works like this: 1. if _expr_'s a lvalue, both T and _ParamType_ are forced to be lvalue references. 2. if _expr_'s a rvalue, the normal (i.e. Case 1) rules apply. ```cpp= template<typename T> void f(T&& param); int x; const int cx; const int& rx; const int* const px; f(x); // T is int&, ParamType is int& f(cx); // T is const int&, ParamType is const int& f(rx); // T is const int&, ParamType is const int& f(px); // T is const int* const &, ParamType is const int* const & f(std::move(x)); // T is int, ParamType is int&& f(std::move(rx)); // T is const int, ParamType is const int&& f(0); // T is int, ParamType is int&& ``` ## Case 3: <span style="color:red">*__ParamType__*</span> is neither a pointer nor a reference 1. if _expr_'s a reference, ignore the reference part 2. then, ignore the [CV qualifier](https://en.cppreference.com/w/cpp/language/cv) ```cpp= template<typename T> void f(T param); int x; const int cx; const int& rx; const int* const px; f(x); // T is int, ParamType is int f(cx); // T is int, ParamType is int f(rx); // T is int, ParamType is int f(px); // T is const int*, ParamType is const int* f(0); // T is int, ParamType is int ``` ## pass an array ```cpp= const char x[] = "0123"; const char *p = x; ``` ```cpp= template<typename T> void f(T param); f(x); // T is const char*, ParamType is const char* f(p); // T is const char*, ParamType is cosnt char* ``` ```cpp= template<typename T> void f(T& param); f(x); // T is const char [], ParamType is const char (&) [] f(p); // T is const char *, ParamType is const char * & ``` ```cpp= template<typename T> void f(T* param); f(x); // T is const char, ParamType is const char* f(p); // T is const char, ParamType is const char* ``` ```cpp= template<typename T> void f(T&& param); f(x); // T is const char (&) [], ParamType is const char (&) [] f(p); // T is const char* &, ParamType is const char* & ``` a trick of reference: ```cpp= template<typename T, size_t N> constexpr size_t sizeofArr(T (&arr) [N]) { return N; } int Key[] = {1,3,5,7,9}; // since the size is evaluate when compiling, // the declaration is legel. int Value[sizeofArr(Key)]; ``` ## pass a function ```cpp= template<typename T> void f1(T param); template<typename T> void f2(T& param); void somefunc(int, double); f1(somefunc); // T is void (*)(int, double), ParamType is void (*)(int, double) f2(somefunc); // T is void (int, double), ParamType is void (&)(int, double) ``` --- reference: - Effective Modern C++ 1/e, Scott Meyers