Зачем нам нужно ключевое слово concept в C++20?

Концепции великолепны, не поймите меня неправильно, но зачем нам для этого еще одно ключевое слово?

Рассмотрим следующий пример:

#include <type_traits>

template <typename T>
concept UnsignedConst = std::is_integral_v<T> && std::is_const_v<T>;

template <UnsignedConst T>
void foo(T bar);

С тем же успехом мы могли бы использовать следующий, на мой взгляд, более простой синтаксис:

/* ... */
template <typename T>
constexpr bool UnsignedConst = std::is_integral_v<T> && std::is_const_v<T>;
/* ... */

Под капотом концепции - это не что иное, как логические константы времени компиляции, зависящие от параметров шаблона (EDIT: НЕТ! См. принятый ответ). Даже requires-предложения можно использовать с шаблонами переменных, поскольку они представляют собой просто выражения, которые оцениваются как логические значения во время компиляции.

🤔 А знаете ли вы, что...
C++ позволяет оптимизировать код на уровне компиляции для повышения производительности.


1
115
1

Ответ:

Решено

Под капотом концепции — это не что иное, как логические константы времени компиляции, зависящие от параметров шаблона.

Это неправда.

concept обладает особыми свойствами, которых нет у простых constexpr bool. В частности, concept не может быть специализированным. Эта неспособность быть специализированным делает возможными правила подчинения понятий. Это позволяет стандарту устанавливать правила для того, что считается «более специализированной» версией шаблона.

Учитывая следующее:

template<typename T>
concept A = atomic_constraint_a<T>;

template<typename T>
concept B = atomic_constraint_a<T> && atomic_constraint_b<T>;

в рамках правил концепций C++ ясно, что A включается в B. Это означает, что любой тип T, который удовлетворяет B, обязательно удовлетворяет A. Следовательно, если у вас есть два шаблона, один ограничен A, а другой — B, если вы передадите тип, удовлетворяющий B, будет выбран именно тот, который будет выбран, даже если есть версия для A.

Специализация разрушит это, потому что кто-то может прийти и специализировать B для типа U таким образом, что A<U> не включает B<U>.

Итак... что должно произойти тогда? Что происходит, когда кто-то пытается предоставить U вышеуказанному шаблону с конкурирующими ограничениями? Первичные ограничения говорят о наличии отношения подчинения, а специализированные - нет.

Что еще более важно, могу ли я даже написать две концепции с отношением подчинения и гарантировать, что это будет поддерживаться? То есть, в мире со специализацией, могу ли я полагаться на подчинение в своих интерфейсах шаблонов?

Нет, единственный способ сделать возможным подчинение — это запретить специализацию. Но шаблоны переменных могут быть специализированными. Итак, теперь вам нужна новая конструкция, которая говорит: «Я похож на эту штуку, но вы не можете специализировать меня». Мы могли бы заставить всех печатать template<typename T> [[nonspecialized]] inline constexpr bool concept_name = X, чтобы получить подчинение (и другие вещи, предусмотренные концепциями).

Или мы могли бы просто сказать template<typename T> concept concept_name = x и убрать кучу синтаксического шума.

Кроме того, concepts не могут быть членами классов. Это тоже важно, так как это означает, что вы не можете иметь де-факто специализацию концепции, специализируя класс вокруг концепции.

Кроме того, делая concept специальной синтаксической конструкцией, представленной собственным грамматическим токеном, это позволяет языку легче использовать concept в новых местах. Например, std::integral auto var_name = func();. Компилятор может видеть, что std::integral — это идентификатор, представляющий понятие. Если он увидит переменную constexpr bool, возможно, вы захотите использовать ее как концепцию. Или вы, возможно, намеревались использовать его как-то иначе. Делая концепции отдельными вещами, мы устраняем любую двусмысленность.

Это то, что позволяет нам по-разному использовать концепции типов в грамматике, что было бы... сложно без специализированного синтаксиса. Может быть, вы могли бы применить атрибут или что-то еще к constexpr inline bool, но опять же... зачем все ключевые слова, когда вы просто имеете в виду concept?