// Szymon Dyszewski - Zadanie dodatkowe, nr albumu: 310625

// Zagadnienie związane z dodaną w C++ 17 Dedukcją argumentów szablonu dla klas (CTAD)

// Zródła:
// https://en.cppreference.com/w/cpp/language/class_template_argument_deduction
// https://www.learncpp.com/cpp-tutorial/class-template-argument-deduction-ctad-and-deduction-guides/
// https://infotraining.bitbucket.io/cpp-17/templates.html
// Dokumentacja do pliku będzie znajdować się w komentarzach

#include <bits/stdc++.h>

using namespace std;

// Definicja szblonu structa Trio będącego przykładem w dalszej części programu
template <typename T, typename U>
struct Trio
{
    T first{};
    T second{};
    U third{};
};

// Zdefiniowanie własnej metody dedukcji wykorzystującej CTAD dla obiektów klasy Trio
template <typename T, typename U>
Trio(T, T, U) -> Trio<T, U>;

int main()
{
    // Specyfikacja argumentów szablonu wprost (C++11)
    pair<int, int> p1{ 1, 2 };
    
    // Wykorzystanie CTAD do deklaracji argumentów szablonu przy inicjalizacji (C++17)
    tuple t(4, 3, 2.5);

    // t zadeklarowane zostało jako <int, int, double>

    pair p2{ 1, 2 };
    auto p3 = pair{ 1, 2 };
    
    cout << (p1 == p2 ? "pair<int, int> p1{ 1, 2 } == pair p2{ 1, 2 }":0) << "\n";
    cout << (p1 == p3 ? "pair<int, int> p1{ 1, 2 } == auto p3 = pair{ 1, 2 }":0) << "\n";



    // Nie można częściowo dedukować argumentów szablonu klasy. 
    // Należy wyspecyfikować lub wydedukować wszystkie parametry z wyjątkiem parametrów domyślnych.
    // Przykład błędnego użycia prowadzącego do błędu kompilacji CTAD:
    // pair p4;
    // pair <int> { 1, 2 };




    // Jeżeli kod służący do dedukcji argumentów szablonu klasy może być zinterpretowany jako przypadek inicjalizacji poprzez kopię, 
    // to kompilator preferuje taką interpretację.

    vector v{1, 2, 3}; // vector<int>
    vector data1{v, v}; // vector<vector<int>>

    // Przyrównanie dwóch powyższych wektorów zwraca błąd kompilacji (wektory przechowują różne typy danych) 
    // cout << (v == data1 ? 1:vector v{1, 2, 3} != vector data2{v, v}) << "\n";

    // Lecz w przypadku, gdy składnia inicjalizacji obiektu pasuje do wywołania konstruktora kopiującego, 
    // wtedy działa specjalna reguła dedukcji argumentu szablonu klasy:
    vector data2{v}; // vector<int>

    cout << (v == data2 ? "vector v{1, 2, 3} == vector data2{v}":0) << "\n";



    // Dzięki zdefiniowaniu metody dedukcji CTAD zdefiniuje za nas typenames jako int, int
    Trio T1{1, 2, 3};
    cout << T1.first << " " << T1.second << " " <<T1.third << "\n";

    // Dzięki zdefiniowaniu metody dedukcji CTAD zdefiniuje za nas typenames jako int, string
    Trio T2{1, 2, "String"};
    cout << T2.first << " " << T2.second << " " <<T2.third << "\n";
    

    return 0;
}
