# Deduction guides
___
## Template deduction
There are three different scenarios during template type deduction:
* Handle by reference or pointer: T& or T* with or without const or volatile
* Handle by value: T with or without const or volatile
* Handle by universal reference: T&& can't use const or volatile here.
___
## Pass by reference
template <typename T>
void function(T& arg) {}
template <typename T>
void constFunction(const T& arg) {}
void foo(int) {}
int main() {
int a = 4;
const int b = 5;
const int& c = a;
int arr[] = {1,2};
function(a); // T -> int | arg -> int&
function(5); // Not compile!
function(b); // T -> const int | arg -> const int&
function(c); // T -> const int | arg -> const int&
function(foo); // T -> void(int) | arg -> void(&)(int)
function(arr); // T -> int[2] | arg -> int(&)[2]
constFunction(a); // T -> int | arg -> const int&
constFunction(5); // T -> int | arg -> const int&
constFunction(b); // T -> int | arg -> const int&
constFunction(c); // T -> int | arg -> const int&
constFunction(foo); // T -> void(int) | arg -> const void(&)(int)
constFunction(arr); // T -> int[2] | arg -> const int(&)[2]
}
___
## Pass by value
template <typename T>
void function(T arg) {}
void foo(int) {}
int main() {
int a = 4;
const int b = 5;
const int& c = a;
int arr[] = {1,2};
char name[] = "Mateusz";
const char* str = name;
const char* const ptr = name;
function(a); // T -> int | arg -> int
function(5); // T -> int | arg -> int
function(b); // T -> int | arg -> int
function(c); // T -> int | arg -> int
function(foo); // T -> void(*)(int) | arg -> void(*)(int))
function(arr); // T -> int* | arg -> int*
function(str); // T -> const char* | arg -> const char*
function(ptr); // T -> const char* | arg -> const char*
}
___
## Pass by universal reference
template <typename T>
void function(T&& arg) {}
void foo(int) {}
int main() {
int a = 4;
const int b = 5;
const int& c = a;
int arr[] = {1,2};
char name[] = "Mateusz";
const char cstr[] = "Mateusz";
const char* str = name;
const char* const ptr = name;
function(a); // T -> int& | arg -> int&
function(5); // T -> int | arg -> int&&
function(b); // T -> const int& | arg -> const int&
function(c); // T -> const int& | arg -> const int&
function(foo); // T -> void(&)(int) | arg -> void(&)(int))
function(arr); // T -> int(&)[2] | arg -> int(&)[2]
function(cstr); // T -> const char(&)[8] | arg -> const char(&)[8]
function(str); // T -> const char(*&) | arg -> const char(*&)
function(std::move(str)); // T -> const char(*) | arg -> const char(*&&)
function(ptr); // T -> const char(*const &) | arg -> const char(*const &)
}
___
## Pass by universal reference - special treatment
When template parameter gets argument by universal reference, deducted type `T` doesn't remove the reference for `l-values`.
In other words: `r-values` are treated as they are passed by value, but `l-values` are treated as a reference.
This is partially true. Scott Meyers said this is an abstraction layer. The real truth is reference collapsing:
* T& & -> T&
* T& && -> T&
* T&& & -> T&
* T&& && -> T&&
___
## auto deduction
`auto` deduction works similar to templates, but there is one exception, which you should remember from previous slajds.