TGViewer
this->notes. this->notes. @thisnotes · 4.51K subscribers
Post #180 1.17K
#cpp

Немного из метапрограммирования 2/2.

3. add_lvalue_reference.

Давайте попробуем написать стандартную метафункцию, добавляющую lvalue ссылку к типу (далее будем опускать написание алиасов _v/_t для краткости):

template <typename T>
struct add_lvalue_reference : type_indentity<T&> {};

add_lvalue_reference_t:
int&& -> int&
int& -> int&
int -> int&


А что для void? Для void ответ void& даст ошибку компиляции, что не очень приятно. Можем сделать частичную специализацию. Только стоит помнить про все возможные комбинации cv-квалификаторов, что означает не одну специализацию, а четыре. Плюс такое решение не является устойчивым во времени: во-первых, на текущий момент void единственный тип, для которого не может быть добавлена lvalue reference, но не будет ли в будущем ещё одного, неизвестно; во-вторых, cv-квалификаторы тоже могут расшириться до условных cvlgbtq-квалификаторов, из-за чего придётся дописать множество специализаций. Очень некрасиво и топорно. Хочется какое-то более аккуратное решение, которое будет работать для всех типов, которые вызывают подобную проблему. Можно сделать вот так:

template <typename T, typename Enable>
struct alr_impl : type_indentity<T> {};

template <typename T>
struct alr_impl<T, remove_reference_t<T&>> : type_indentity<T&> {};

template <typename T>
struct add_lvalue_reference : alr_impl<T, remove_reference_t<T>> {};


Работает это просто. Для вызова add_lvalue_reference<SomeType> происходит попытка сматчить вызов и частичную специализацию (т.к. частное всегда предпочтительнее общего). В этой специализации делается remove_reference_t<T&>, что для cv void не скомпилируется -> случается SFINAE -> специализация выбрасывается из списка кандидатов и выбирается базовый шаблон.
Этот код конечно можно упростить:

template <typename T, class Enable>
struct alr_impl : type_indentity<T> {};

template <typename T>
struct alr_impl<T, void_t<T&>> : type_indentity<T&> {};

template <typename T>
struct add_lvalue_reference : alr_impl<T, void> {};


В частичной специализации делается проверка на то, является ли выражение T& well-formed. Если да, то специализация для <T, void> срабатывает.

Аналогичным способом можно реализовать add_rvalue_reference, add_pointer и много других type traits.

Пример отсюда. Там можно посмотреть и несколько других более нетривиальных примеров.

4. Различные вычисления на компиляции могут замедлять время сборки вашего проекта. И вам может захотеться что-то сделать с этим. Но как померять время компиляции? Для clang в этом вам поможет флаг -ftime-trace. Я так долго откладывал рассказ об этом флаге, что кто-то уже это сделал, причём с разбором того, как это работает.

5. И из повседневных мелочей.
- Вот так интересно можно юзать кастомный компаратор для std::set:

bool cmp(X a, X b) { ... }
using Cmp = std::integral_constant<decltype(&cmp), &cmp>;
std::set<X, Cmp> st;


Лёгким движением руки мы сделали из функции структуру.

- Мне нравится, что посчитать N-е Фибоначчи втупую (через N-1 и N-2 числа) на шаблонах работает за O(n), когда через constexpr функцию за O(n!). Просто потому что инстанцирование шаблонов == мемоизация вычисленных значений.
- Вы можете написать почти все type trait’ы с помощью C++ (кроме очень специфических вроде is_union, is_class и др.), но в стандартных библиотеках множество из них реализуются через compiler intrinsics, т.к. это тупо быстрее.


Но вообще лишний раз подумайте, нужно ли вам заниматься чем-то подобным. На самом деле большинство проблем, которые вы можете захотеть решить метапрограммированием/SFINAE, решаются без этих инструментов гораздо проще и понятнее. Или ищите готовое (например в бусте). А лучше переходите на C++20.
  • 👍 8
  • 🔥 1
More from @thisnotes
  1. Sep 25, 2026Спасибо большое!
  2. Sep 25, 2026Post #525
  3. Sep 25, 2026Post #524
  4. Sep 25, 2026Post #523
  5. Sep 25, 2026Post #522
  6. Sep 25, 2026Post #521
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →