шаблоны - это паттерн, по которому компилятор должен сгенерировать код шаблоны - полностью 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::template A<10> x в C++20 уменьшили количество контекстов, в которых зависимая переменная воспринимается как expression

если есть шаблонный наследник от шаблонного родителя, то при обращении к полю шаблонного родителя, компилятор не лезет в код шаблонного родителя. чтобы починить надо написать ++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); это будет значить, что здесь мы собираемся использовать шаблонную функцию от конкретных типов, но при этом хотим, чтоб компилятор не истанцировал эту версию, а поверил, что такая версия где-то уже истанцирована и чтоб линковщик нашёл и подвязал

type deduction type erasure metafunctions