метафункция - это шаблонная структура, которая содержит тип или значение

template <auto Value>
struct value_identity {
	static constexpr value = Value;
	using type = decltype(value);
};
...
auto x = value_identity<239>::value;
 
template <typename T>
constexpr auto value = value_identity<T>::value;
 
template <typename T>
using value_identity_t = value_identity<T>::type

std::conjunction, std::disjunction, std::negation - метафункции над типами, которые сами по себе метафункции. нужны, когда мы хотим проверить несколько условий про тип

SFINAE = subtitution failure is not an error если в момент инстанцирования объявления функции (когда шаблон пытается подставить тип в объявление функции) получается некорректный тип, то это не ошибка компиляции, а компилятор просто не будет рассматривать эту версию перегрузку. рассматривается следующий кандидат на перегрузку выведется 1, 2

первая версия предпочтительнее, но при подстановке в объявление функции int, получился невалидный тип, поэтому та версия перегрузки откидывается

SFINAE работает только в объявлении. тело функции истанцируется уже после того, как выбрана версия перегрузки

как сделать так, чтобы при вызове от integral type выбиралась одна версия перегрузки, а для всех остальных другая?

std::enable_if - если получает true первым аргументом, то, имеет внутри себя алиас на второй аргумент. если false, то это пустая структура и std::enable_if_t будет невалидный тип и вся функция с std::enable_if_t выкинется из кандидатов

auto f(T x) -> decltype(x%2) - для типов, у которых определен оператор %

шаблонные функции, как и обычные, не могут отличаться в сигнатуре лишь параметром по умолчанию поэтому здесь - redefinition (возникает на ранней стадии компиляции, до подстановки типа в шаблон) хотя если добавить ещё шаблонный аргумент по умолчанию, то сработает

чтобы повлиять на выбор перегрузки шаблонной функции, мы должны передать в неё аргумент вида std::enable_if<constexpr condition, bool> и сделать его по умолчанию = true/false (не важно) если условие выполняется, то будет bool = true а если нет, то будет невалидный тип = true -> эта версия перегрузки не выберется

если сделать несколько функций с не взаимоисключающими параметрами (в одной enable_if<is_integral>, в другой enable_if<is_bool>), то будет CE - ambigous call

std::conjunction implementation

не конченная реализация:

template <typename...> 
struct conjunction : std::true_type {}; 
 
template <typename B1, typename... Bn> 
struct conjunction<B1, Bn...> : std::conditional_t<B1::value
								, conjunction<Bn...> //if true check more
								, B1  //if false
								> {};

is_class implementation

пытаемся понять тип, от которого наследуемся. для этого нужно знать возвращаемый тип функции test с шаблонным параметром T от nullptr. выбираем сигнатуру функции наследуется от true_type, если у этого типа могут быть указатели на члены, они существуют только у классовых типов и не важно есть ли на самом деле там такой член типа int, тип сам по себе корректный наследуется от false_type во всех других случаях

is_pointer implementation

перегрузка функции по T и T* перегрузка по T и T* с помощью requirement’а

is_polymorphic implementation

наследуемся от результата функции. выбираем сигнатуру функции первый кандидат: кастим nullptr к T* - всегда возможно. делаем dynamic_cast от T* к void*. такое dynamic_cast может делать только от полиморфных типов. значит если тип не полиморфный, то кандидат отбрасывается (кастим к const volatile тк если у нас изначально были cv-квалификаторы, то мы не можем их просто отбросить, а навесить - запросто)

has_method_construct implementation comma trick - засчёт оператора запятая тип выражения всегда такой, какой нужно, но само выражение корректно или некорректно в зависимости от сущестовования метода construct

как реализована std::declval<T>?

template <typename T> std::add_rvalue_reference::type declval() noexcept` - как T&&, но для void норм возвращает либо rvalue&, либо lvalue&, чтоб не надо было создавать T, тип вдруг он абстрактный

не имеет определения. нужна только для метапрограммирования и юзается почти всегда под decltype. в любом случае вычисляется в compile time. если попытаться вызваться в контексте runtime вычислений, то будет ошибка линкера

T&& потому что если T - imcomplete type, то возвращение объекта imcomplete type даже в unevaluated context - CE крч чтоб вернуть T из функции, компилятору нужно знать определение T. навесив && мы можем использовать declval даже с типами без определений

is_copy_constructible implementation

is_constructible & is_copy_constructible & is_move_constructible implementation

is no_throw_move_constructible implementation is_nothrow_move_constructible implementation v2:

std::is_convertible

разница между std::is_constructible и std::is_convertible в том, что первое не проверяет implicit convertions

создаём ссылку на функцию, которая принимает To по значению и возвращает войд и в эту функцию пытаемся отдать From и проверяем корректно ли

std::common_type

принимает типы и возвращает общий для них тип. общий тип - такой, что все типы к нему приводятся как по двум данным типам получить общий? - результат тернарного оператора будет общим для них типом однако тернарный оператор не сможет найти общего родителя, если он не присутствовал среди типов также и std::common_type не найдёт общего родителя + важно в каком порядке передавать “сына”, “дочь” и “маму”, ведь на комбинации “мама, сын, дочь” будет CE

std::type_identity<T> - структура, в которой написано using type = T; такая реализация common_type - не SFINAE-friendly, тк даже если common type’а нету, он всё равно проистанцирует шаблонную структуру, попытается вычистить тернарный оператор и упадёт c С++11 она стала SFINAE-friendly

SFINAE-friendliness

если функция не SFINAE-friendly, то её нельзя использовать в контексте SFINAE функция не SFINAE-friendly, если чтобы понять её тип, нужно истанцировать её тело. при инстанцировании может возникнуть CE

void() тк нужен экспрешен. крч это void созданный по умолчанию. если бы было просто void, то была бы синтаксическая ошибка, тк под decltype должен быть экспрешен

некоторые type_traits нельзя реализовать стандартными средствами языка, например std::is_standart_layout, std::is_abstract, std::is_aggregate, они зашиты в компилятор

проверить, что тип T есть в пакете Ts или

поиск корня числа за логарифм в compile-time

перевод двоичного числа в десятичное в compile-time: чутка ублюдошная хуйня

constraints and requirements