# Deduction guides
___

## Template deduction

There are three different scenarios during template type deduction:

* <!-- .element: class="fragment fade-in" --> Handle by reference or pointer: <code>T&</code> or <code>T*</code> with or without <code>const</code> or <code>volatile</code>
* <!-- .element: class="fragment fade-in" --> Handle by value: <code>T</code> with or without <code>const</code> or <code>volatile</code>
* <!-- .element: class="fragment fade-in" --> Handle by universal reference: <code>T&&</code> can't use <code>const</code> or <code>volatile</code> here.

___

## Pass by reference

<pre><code class="cpp" data-trim data-noescape>
template &lt;typename T&gt;
void function(T& arg) {}

template &lt;typename T&gt;
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);        <span class="fragment">// T -> int | arg -> int&</span>
    function(5);        <span class="fragment">// Not compile!</span>
    function(b);        <span class="fragment">// T -> const int | arg -> const int&</span>
    function(c);        <span class="fragment">// T -> const int | arg -> const int&</span>
    function(foo);      <span class="fragment">// T -> void(int) | arg -> void(&)(int)</span>
    function(arr);      <span class="fragment">// T -> int[2] | arg -> int(&)[2]</span>
    constFunction(a);   <span class="fragment">// T -> int | arg -> const int&</span>
    constFunction(5);   <span class="fragment">// T -> int | arg -> const int&</span>
    constFunction(b);   <span class="fragment">// T -> int | arg -> const int&</span>
    constFunction(c);   <span class="fragment">// T -> int | arg -> const int&</span>
    constFunction(foo); <span class="fragment">// T -> void(int) | arg -> const void(&)(int)</span>
    constFunction(arr); <span class="fragment">// T -> int[2] | arg -> const int(&)[2]</span>
}
</code></pre>

<!-- .slide: style="font-size: 0.70em" -->
___

## Pass by value

<pre><code class="cpp" data-trim data-noescape>
template &lt;typename T&gt;
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);        <span class="fragment">// T -> int | arg -> int</span>
    function(5);        <span class="fragment">// T -> int | arg -> int</span>
    function(b);        <span class="fragment">// T -> int | arg -> int</span>
    function(c);        <span class="fragment">// T -> int | arg -> int</span>
    function(foo);      <span class="fragment">// T -> void(*)(int) | arg -> void(*)(int))</span>
    function(arr);      <span class="fragment">// T -> int* | arg -> int*</span>
    function(str);      <span class="fragment">// T -> const char* | arg -> const char*</span>
    function(ptr);      <span class="fragment">// T -> const char* | arg -> const char*</span>
}
</code></pre>

<!-- .slide: style="font-size: 0.80em" -->
___

## Pass by universal reference

<pre><code class="cpp" data-trim data-noescape>
template &lt;typename T&gt;
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);              <span class="fragment">// T -> int& | arg -> int&</span>
    function(5);              <span class="fragment">// T -> int | arg -> int&&</span>
    function(b);              <span class="fragment">// T -> const int& | arg -> const int&</span>
    function(c);              <span class="fragment">// T -> const int& | arg -> const int&</span>
    function(foo);            <span class="fragment">// T -> void(&)(int) | arg -> void(&)(int))</span>
    function(arr);            <span class="fragment">// T -> int(&)[2] | arg -> int(&)[2]</span>
    function(cstr);           <span class="fragment">// T -> const char(&)[8] | arg -> const char(&)[8]</span>
    function(str);            <span class="fragment">// T -> const char(*&) | arg -> const char(*&)</span>
    function(std::move(str)); <span class="fragment">// T -> const char(*) | arg -> const char(*&&)</span>
    function(ptr);            <span class="fragment">// T -> const char(*const &) | arg -> const char(*const &)</span>
}
</code></pre>

<!-- .slide: style="font-size: 0.74em" -->
___

## 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:
<!-- .element: class="fragment fade-in" -->
* <!-- .element: class="fragment fade-in" --> <code>T& &</code> -> <code>T&</code>
* <!-- .element: class="fragment fade-in" --> <code>T& &&</code> -> <code>T&</code>
* <!-- .element: class="fragment fade-in" --> <code>T&& &</code> -> <code>T&</code>
* <!-- .element: class="fragment fade-in" --> <code>T&& &&</code> -> <code>T&&</code>

___

## auto deduction

`auto` deduction works similar to templates, but there is one exception, which you should remember from previous slajds.

<div class="multicolumn">
<div class="col">

```C++
auto val = 5;
```
is equal to

```C++
template <typename T>     
void foo(T val);
```
</div>
<!-- .element: class="fragment fade-in" -->
<div class="col">

```C++
const auto& val = 5;
```
is equal to

```C++
template <typename T>     
void foo(const T& val);
```
</div>
<!-- .element: class="fragment fade-in" -->
<div class="col">

```C++
auto&& val = 5;
```
is equal to

```C++
template <typename T>     
void foo(T&& val);
```
</div>
<!-- .element: class="fragment fade-in" -->
</div>
___

## auto deduction - one exception

```C++
template <typename T>
void foo(T t) {}

auto val = {1, 2, 3, 4}; // std::initializer_list<int>
foo({1, 2, 3, 4}); // deduction failed!
```
<!-- .element: class="fragment fade-in" -->
Need to explicity use `initializer_list`
<!-- .element: class="fragment fade-in" -->

```C++
template <typename T>
void foo(std::initializer_list<T> t) {}

auto val = {1, 2, 3, 4}; // std::initializer_list<int>
foo({1, 2, 3, 4}); // std::initializer_list<int>
```
<!-- .element: class="fragment fade-in" -->
___

## auto in generic lambda

In generic lambda `auto` uses the same deduction rules like for templates not for `auto`! This happens because, lambda is struct, so generic lambda is a template structure.

<div class="col">

```C++
auto lambda = [](auto&& first, const auto& second, auto third) {}
```
is equal to

```C++
struct Lmabda {
    template <typename X, typename Y, typename Z>
    auto operator()(X&& x, const Y& y, Z z) const {

    }
};
```
</div>
<!-- .element: class="fragment fade-in" -->

___

## std::forward once more

If we want to perfect forward some value in template you will write:
<!-- .element: class="fragment fade-in" -->

```C++
template <typename T>
void fun(T&& t) {
    other(std::forward<T>(t));
}
```
<!-- .element: class="fragment fade-in" -->
But how to do this in lambda? We know that generic lambda is a teplate, but we don't have an access to `T`!
<!-- .element: class="fragment fade-in" -->

```C++
auto lambda = [](auto&& t) {
    other(std::forward<decltype(t)>(t));
};   
```
<!-- .element: class="fragment fade-in" -->
___

## decltype

Decltype return a type of variable, without removing `references` or `const`/ `volatile` qualifiers

```C++
int x = 5;
decltype(x) y; // int

const int num = 20;
decltype(num) num2 = 30; // const int

const int& ref = num;
decltype(ref) ref2 = x; // const int&

const char name[] = "Mateusz";
decltype(name) name2 = "Scott"; // const char[]

decltype(foo) fun; // void fun(int, const string&

auto pred = [](int num){ return num % 1 == 0; };
decltype(pred(20)) val; // bool

std::vector<int> vec{1};
decltype(vec.begin()) it; // std::vector<int>::iterator
decltype(vec[0]) // int&
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->
___

## decltype - one problem

What is wrong with this snippet of code?

```C++
void authorize() {}

template <typename C>
auto authorizeAndAccess(C& container, size_t index) {
    authorize();
    return container[index];
}

int main() {
    std::vector<int> vec{1,2,3};
    authorizeAndAccess(vec, 2) = 10;
    std::cout << vec[2] << '\n';
}
```
<!-- .element: class="fragment fade-in" -->

```C++
error: lvalue required as left operand of assignment authorizeAndAccess(vec, 2) = 10;
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->
___

## decltype - partial solution

The same result we can achieve by using `decltype(auto)`.
<!-- .element: class="fragment fade-in" -->

```C++
void authorize() {}

template <typename C>
auto authorizeAndAccess(C& container, size_t index) -> decltype(container[index]) {
    authorize();
    return container[index];
}

int main() {
    std::vector<int> vec{1,2,3};
    authorizeAndAccess(vec, 2) = 10;
    std::cout << vec[2] << '\n';
}
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->
___

## decltype - when solution make another trouble

What is wrong now?
<!-- .element: class="fragment fade-in" -->

```C++
void authorize() {}

template <typename C>
decltype(auto) authorizeAndAccess(C& container, size_t index) {
    authorize();
    return container[index];
}

int main() {
    const auto res = authorizeAndAccess(std::vector<int>{5, 8, 12, 16}, 2);
    std::cout << std::boolalpha << "res: " << res << '\n';
}
```
<!-- .element: class="fragment fade-in" -->

```C++
cannot bind non-const lvalue reference of type ‘std::vector<vec>&’ to an rvalue of type ‘std::vector<int>’
const auto res = authorizeAndAccess(std::vector<int>{5, 8, 12, 16}, 2);
```
<!-- .element: class="fragment fade-in" -->
<!-- .slide: style="font-size: 0.8em" -->

___

## decltype - final fix

```C++
void authorize() {}

template <typename C>
decltype(auto) authorizeAndAccess(C&& container, size_t index) {
    authorize();
    return std::forward<C>(container)[index];
}

int main() {
    const auto res = authorizeAndAccess(std::vector<int>{5, 8, 12, 16}, 2);
    std::cout << std::boolalpha << "res: " << res << '\n'; // will print 12
}
```
<!-- .slide: style="font-size: 0.95em" -->