tuple - кортеж из нескольких элементов нескольких типов
обобщение пары, но на перменное количество типов
можно иметь в шаблонных параметрах повторяющиеся типы, они будут храниться в порядке объявления

std::get - внешняя шаблонная функция, принимающая tuple как аргумент, а шаблонный параметр - constexpr число (индекс элемента tuple) через std::get можно также обратится к std::array и std::variant возвращаемый тип - decltype(auto). достает k-ый элемент и возвращает его если const tuple, то и возвращаемый элемент должен быть const аналогично с видом value
почему std::get - внешняя функция, а не метод tuple?
потому что если бы мы вызывали метод get из шаблонного tuple, то нам бы пришлось писать template перед get

structured bindings (C++17) - объявление нескольких новых переменных применимы к tuple’ам, парам, структурам (которые допускают агрегатную инициализацию) и array’ам (сишным тоже)
std::tuple t{1, 2.0, 'a'}
auto [x, y, z] = t;распаковка tuple теперь x = 1, y = 2.0, z = ‘a’, причём типы у них автоматически выведены
auto&& [x, y, z] = t; - элементы lvalue или rvalue в зависимости от вида value tupl’а
for (const auto& [key, value] : map {} - range based for на максималках
с C++23 можно указывать переменные _ в одной области видимости в количестве нескольких штук, если они нам не нужны от распаковки
3 способа создать tuple (кроме стандартного std::tuple<Args…> = init_list):
- по аналогии с функцией std::make_pair есть функция std::make_tuple. берёт аргументы и делает tuple из них с отбрасыванием ссылок. с появлением CTAD стала менее нужной
- std::tie - берёт аргументы и делает tuple из lvalue&
- std::forward_as_tuple - берёт аргументы и делает их них tuple, сохраняя вид value каждого аргумента

применимость std::tie
определить лексикографическое сравнение между полями структуры - сравнивать их как tuple (std::tie чтоб не копировать, а сравнивать по ссылке)
одной строчкой присвоить 2 переменным значение из пары. создаётся временный tuple, содержащий ссылки на переменные
неявные конверсии при присваивании tuple к tuple разрешены

std::ignore - глобальная структура ignore_t в пространстве std, которой можно что угодно присвоить и ничего не произойдёт
ещё один способ явно указать, что параметр не используется 1 способ: не дать ему имя 2 способ: дать ему имя, но в теле написать std::ignore = имя;
но исходно std::ignore была придумана, чтобы делать распаковку tuple/pair, но не присваивая ненужные аргументы
std::tie(iter, std::ignore) = set_.insert(value)
std::piecewise_construct - тэг, который подаётся первым аргументом в пару, чтобы дальше 2 и 3 аргументом подать tuple’ы с аргументами, из которых сконструировать первый элемент пары и второй
пригождается, если мы что-то хотим emplace в map, будет ожидаться пара и мы хотим сконструировать объекты на месте
m.emplace(std::piecewise_construct
, std::forward_as_tuple("c")
, std::forward_as_tuple(10, 'c');идея реализации tuple:

std::tuple_cat - конкатенация tuple’ов. берётся переменное количество tuple и создаётся из их элементов tuple
реализация в первом приближении:
не очень хорошая, тк слишком много копирования tuple’ов
с C++20 дефолтный конструктор stl tuple - conditionally explicit он explicit тогда и только тогда, если какой-нибудь элемент нельзя инициализировать через {}
это сделано через explicit (compile-time условие)
иногда хочется выключать некоторые версии перегрузки из рассматриваемых
для этого есть std::enable_if - это такая структура, которая первым параметром принимает bool, а вторым - какой-то тип, по умолчанию void
если первый параметр false - то это пустая структура
а если true, то в теле этой структуры написан typedef T type
здесь если условие верное, то std::enable_if превратится в bool и будет bool = true
а если неверное, то будет void = true - void некорректный тип. но есть такое правило, что эта версия перегрузки просто выключится из множества рассматриваемых версий
то есть чтобы уметь выключать те или иные версии шаблонных перегрузок в зависимости от compile-time условий, нужно последним аргументом передать std::enable_if_t<метафункция, bool> = true