Ответ вслух Senior Шаблоны и концепты обновлено

Концепты против SFINAE

Вопрос

Как ограничить шаблон функции только числовыми типами? Покажите путь через SFINAE и через концепты и сравните.

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

До C++20 ограничение делали через SFINAE: добавляли в сигнатуру std::enableift<std::isarithmeticv<T, int = 0 или подставляли его в возвращаемый тип. Если тип не подходил, подстановка проваливалась, и перегрузка тихо исчезала из списка кандидатов.

Что должно прозвучать в ответе

  • SFINAE: `std::enable_if_t<std::is_arithmetic_v<T>>` в возвращаемом типе или параметре шаблона

  • Минусы SFINAE: нечитаемо, огромные ошибки, сложно делать взаимоисключающие перегрузки

  • Концепты: `template <Number T>` или `requires`, стандартные `std::integral`, `std::floating_point`

  • Перегрузка по концептам: выбирается более ограниченный кандидат

  • Ошибки сообщают, какое требование не выполнено

  • static_assert как простой вариант, если перегрузка не нужна

Что могут спросить следом

  • Чем requires-клауза отличается от requires-выражения?
  • Как работает subsumption концептов?

Разбор

До C++20 ограничение делали через SFINAE: добавляли в сигнатуру std::enable_if_t<std::is_arithmetic_v<T>, int> = 0 или подставляли его в возвращаемый тип. Если тип не подходил, подстановка проваливалась, и перегрузка тихо исчезала из списка кандидатов. Работает, но читается плохо, ошибки на несколько экранов, а для двух взаимоисключающих перегрузок приходится аккуратно писать противоположные условия. В C++20 я пишу концепт template <class T> concept Number = std::integral<T> || std::floating_point<T>; и ограничиваю шаблон template <Number T>. Требования видны в объявлении, ошибка говорит, какое требование не выполнено, а при перегрузке компилятор выбирает более ограниченный вариант, если один концепт включает другой. Для сложных требований есть requires-выражения, проверяющие, что выражение компилируется и даёт нужный тип. Если перегрузка не нужна и хочется просто понятной ошибки, хватает static_assert внутри шаблона.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.