шаблоны - это паттерн, по которому компилятор должен сгенерировать код
шаблоны - полностью compile time концепция
можно объявлять шаблоны функций, классов и шаблонные алиасы (юзинги) (С++11)

с С++14 можно делать шаблонные переменные (разные константы для разных типов) с С++20 можно в шаблонах объявлять концепт
если передать в шаблон для одного типа подать 2 разных типа, то компилятор не поймёт (CE), если не указать ему тип явно стадия генерации должна пройти полностью целиком до выбора версии
- сначала перегрузка шаблонов (выбор наиболее подходящего шаблона (выбираются шаблоны по принципу более частный из подходящих) или он вообще не нужен)
- потом инстанцирование шаблонов (в шаблон подставляются аргументы и происходит выбор специализации, генерируются нужные версии)
- потом выбор перегрузки функции
разные версии для разных типов - это разные классы, между ними нет конверсии, если не определить
если параметр шаблона не используется, то можно не писать его имя - также, как для функций
template <typename T, typename = T::value_type>
перегрузка шаблонных функций
частное предпочтительнее общего - если есть шаблонная функция для любого типа и есть функция с таким же именем и с определённым типом, то шаблонная не сгенерируется
но точное соответствие лучше, чем каст - то есть если определена функция для типа, к которому можно скастить, то сгенерируется шаблонная функция, для того типа
если явно указать шаблонный параметр, то полюбому сгенерирует
если написать 2 одинаковых по параметрам и названию функции шаблоны, то CE redefinition даже без инстанцирования
можно писать шаблонные аргументы по умолчанию
template <typename T, typename U = int>
U f(T x) { return 0; }void f(T& x), void f(T x)
f(y) // CE ambigous callшаблонный конструктор поглотит конструктор копирования, тк если копироваться не от константного объекта, то выбор шаблонного конструктора предпочтительнее
специализации шаблонов
начинается с template<>
полная специализация: чтобы для каких-то типов шаблон имел другую реализацию, нежели для других типов
частичная специализация: один аргумент фиксирован, а другой произвольный или специализация только для указателей/констант/ссылок любого типа

специализация шаблонных функций:
отличается от перегрузки шаблонных функций тем, что имеет более низкий приоритет перегрузки
порядок имеет значение, выведется 2 (2 специализация 1)
сначала выбирается перегрузка, а только потом специализации
для функций запрещены частичные специализации! потому что она лишена смысла, у нас есть перегрузка
числовые параметры шаблонов должны быть constexpr и целочисленными (до С++20)
ещё есть шаблонные шаблонные параметры (template template parameters) чтоб передавать как шаблонный параметр другой шаблон
здесь с C++17 вместо class можно написать тоже typename
у шаблонов есть глубина инстанцирования шаблонов, если превышает - fatal error и падает
есть флаг компиляции -ftemplate-depth=10000000 из-за которого может произойти segfault signal terminated program cc1plus — segfault в compile time
тут было сгенерено 20 структур и вычисление происходит за линейное время
(static const => constexpr, но указываем явно, чтобы явно)

шаблонная переменная - метафункция

dependent names
если в шаблоне есть имя, которое в неймспейсе шаблона, то он в любом случае парсит его, как expression, а не как имя типа. чтобы он парсил его как имя типа, нужно перед зависимым именем написать typename
typename S<T>::A* x; - declaration, A - имя типа
S<T>::A - переменная из неймспейса S
а если A - шаблон, то нужно написать `typename S
если есть шаблонный наследник от шаблонного родителя, то при обращении к полю шаблонного родителя, компилятор не лезет в код шаблонного родителя. чтобы починить надо написать ++this->x (x - поле шаблонного родителя) или ++Base<T>::x, тогда это не будет dependent name если мы хотим явно обратиться к полю шаблонного родителя из наследника, то нам нужно явно указывать this
Two phase translation
когда компилятор компилирует шаблонный код, он это делает в 2 прохода
первый - до подстановки Т (синтаксический, семантический), второй - после.

<type_traits> (С++11)
метафункции - это функции, которые принимают типы и возвращают типы или принимают типы и возвращают значения std::is_same<T, U> - структура, которая содержит метафункцию, которая по двум типам возвращает bool
std::true_type - метафункция, в которой написано static const bool value = true std::false_type - метафункция, в которой написано static const bool value = false чтоби каждый раз не писать такое для метафункций, можно просто наследоваться от true_type или false_type и автоматически будет такое поле std::integral_constant<type, value> - метафункция, в которой написано static const type::value = value std::rank - рекурсивная шаблонная подстановка, которая возвращает размерность массива, а для немассивов - 0
std::conditional - тернарный метаоператор (тернарный оператор для типов), принимает <bool, type T, type F> и возвращает T или F
в C++14 добавили шаблонные юзинги в <type_traits>: (спустя 3 года после введения шаблонных юзингов) можно вместо typename conditional<B, T, F>::type писать conditional_t
в C++14 добавили шаблонные переменные, а в C++17 их добавили в <type_traits>, и доопределили const bool is_same_v = is_same<T, U>::value
variadic templates (C++11) - шаблоны с переменным количеством аргументов
template<typename... Types> // Types - пакет типов
void f(Types... tx) // tx - пачка переменных. типы могут быть разными`пакет можно распаковать (первое … - объявление пачки, а второе … - распаковка)
для распаковки откусывают голову
2 структура это специализация 1 структуры и она подходит под сигнатуру (… Types пустой)
print можно переписать как std::cout << … << tail; с помощью fold expression
sizeof…(tail); - встроенный оператор сайзофмноготочие, его можно вызывать от пакетов. возвращает в compile time число пакетов. можно вызывать как от пакета переменных, так и от пакетов типов. тоже работает на шаблонной рекурсии
void f(…) {} - C-style variadic function
Fold expressions (C++17) - выражение свёртки
… делает “и так далее” для пакета
fold expression - expression, в котором фигурирует пакет и бинарным оператором соединяем с многоточием. разворачивается в compile time. означает: для всех типов из пакета повтори вот эту операцию
разница между 1 и 2
1 правоассоциативен, 2 левоассоциативен
CRTP - паттерн Curiously Recurring Template Pattern имитация виртуальных функций — это идиома проектирования, заключающаяся в том, что класс наследует от базового шаблонного класса с самим собой в качестве параметра шаблона базового класса. (базовый класс принимает наследника как шаблонный аргумент. в наследнике суем себя базовому классу в шаблонный параметр)
template <typename T>
class base{};
template <typename T>
class derived : public base<derived<T>> {};
/* Такая конструкция делает возможным обращение к производному классу из базового. */
fold expression to stop when condition is satisfied
&& if to stop when false
explicit template specialisations
можно явно истанцировать шаблон. заставит компилятор сгенерировать шаблон прям на этом месте
основное применение: скрыть определение шаблонных функций
можно в хедере написать только объявление, в .cpp написать определение, а в конце явное истанцирование нужной специализации
попытка вызова этого шаблона от других типов приведёт к ошибке линкера, тк определения для них нет
поможет уменьшить время компиляции
продолжение этой идеи - extern template
можно написать extern template void f<int>(int);
это будет значить, что здесь мы собираемся использовать шаблонную функцию от конкретных типов, но при этом хотим, чтоб компилятор не истанцировал эту версию, а поверил, что такая версия где-то уже истанцирована и чтоб линковщик нашёл и подвязал