Templates (еще глубже!)

среда, апр. 23, 2025 | 3 минуты чтения

Templates (еще глубже!)

2 семестр
Основы программирования.

Дописываем тюпл!!!!

  • Getter

    • Делаем шаблонную рекурсию
    template<size_t N, typename Head, typename... Tail>
    struct Getter<N, Head, Tail...> {
    	using value_type = Getter<N-1, Tail...>::value_type;
    };
    
    template<typename Head, typename... Tail>
    struct Getter<0, Head, Tail...> {
    	using value_type = Head;
    };
    
    • В шаблоничке лежит число-индекс элемента из tuple
      • как всегда делаем шаблончик, потом специализация с откусывание одного элемаента
      • отдельная специализация для элемента 0 - конец рекурсии
      • Когда доходим до нолика, значит дошли до нужного значения и можем возвращать t
    • СЛишком громозко
      • Не хочется перечислять все типы в tuple
      • А сможет ли функция сама задедадктить из tuple аргументы?
      • CTAD не можем, отому что для этого нужен конструткор
      • Тогда попробуем TAD
        • Сделаем шаблонную функцию, которая будет протягивать типы
        • Просто вызовем в ней геттер от нужного tuple
        • засчёт шаблона tuple компилятор задедактит аргументы геттера
      • Сделаем функцию make_tuple, которая сама задедактит все типы для tuple и будет счастье
  • Как вывести тип для конструирования вектора, если мы его будем конструировать от итераторов

  • Можно делать подсказки внутри функций для компилятора (см слайд)

overload Pattern

  • (было раньше)

  • Делали класс, в который клали 2 лямбды, а потом использовали оператор() от обеих этих лямбд

  • Засчёт того, что они принмают разные типы аргументов, Выбирался тот тип скобочек, который нужен

  • Теперь можем делать также, но уже с целым списком аргументов

std::variant

  • Строго типизированный union(в отличие от структуры хранит одно из полей)
  • Решает проблему union в том, что нужно всегда помнить тип
  • Типичное использование:
    • Конструктор понимает, какой тип мы в него кладём
    • Не кастит типы
    • в гете прописываем тип, который там лежит и хоти достать
    • если там лежит инт(11), то достать лонг не получится (не кастит никак)

std::visit

  • Мёрджим оператор паттерн и std::variant
  • Вызываем std::visit от overload pattern-класса и std::variant, и тогда вызовется функция под тот тип, который лежит в std::variant

Подумать, хау ит ворк

Variadic CRTP (см слайдик)

  • Берём дерайвд, наследуем от бейз, но по шаблону дерайвд
  • Теперь хотим делать также, но теперь от нескольких аргументов
    • Наследуем класс от класса, который наследует сам класс, тогда и тут прописываем шаблоны
    • из-за того, что там классы тоже шаблонные, то в шаблоне надо указать, что аргументы шаблонные ( просто ставим < typename >……)

МЕТАПРОГРАММИРОВАНИЕ ЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫЫАААААААААААААААААААА

  • Compile-time evaluation
  • Шаблончик работает как приём аргументов
  • Экономим на времени в рантайме
  • Только все данные для вычисления уже должны быть известный до компиляции

constexpr

  • Позволяет функции или переменной быть вычисленной в compile-time

  • Если есть возможность в compile-time, то там и вычислится, а иначе в ран-тайме

  • constexpr variable

    • Литеральный тип
    • Инициализация через константное выражение (явно, constexpr функция и тд)
  • constexpr function

    • Возвращает литеральный тип
    • Содержит переменные литеральных типов
    • Не виртуальная
    • Без исключений и тд
  • Теперь достаточо просто написать слово constexpr, а не все эти изощрения с enum