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