C ++ 20 имеет механизм для принятия решения, когда одна конкретная ограниченная сущность «более ограничена», чем другая. Это не простая вещь.
Это начинается с концепции разбиения ограничения на его атомарные компоненты, процесс, называемый нормализацией ограничения . Это большой и слишком сложный вопрос, но основная идея состоит в том, что каждое выражение в ограничении рекурсивно разбивается на его элементарные концептуальные части, пока вы не достигнете под-выражения компонента, которое не является концептом.
Поэтому , учитывая , что взгляд давайте на то, как integral
и signed_integral
понятия определены :
template<class T>
concept integral = is_integral_v<T>;
template<class T>
concept signed_integral = integral<T> && is_signed_v<T>;
Разложение integral
просто is_integral_v
. Разложение signed_integral
есть is_integral_v && is_signed_v
.
Теперь мы подошли к понятию подчинения ограничения . Это довольно сложно, но основная идея состоит в том, что ограничение C1, как говорят, «включает» ограничение C2, если разложение C1 содержит каждое подвыражение в C2. Мы можем видеть , что integral
не подводить signed_integral
, но signed_integral
делает подводить integral
, так как она содержит всеintegral
делает.
Далее мы подходим к упорядочению ограниченных объектов:
Объявление D1, по крайней мере, столь же ограничено, как и объявление D2, если * D1 и D2 оба являются ограниченными объявлениями, а связанные с D1 ограничения относятся к ограничениям D2; или * D2 не имеет связанных ограничений.
Поскольку signed_integral
включает в себя integral
, <signed_integral> wrapper
«по крайней мере так же ограничен», как <integral> wrapper
. Тем не менее, обратное неверно из-за необратимого включения.
Следовательно, в соответствии с правилом для «более ограниченных» объектов:
Объявление D1 более ограничено, чем другое объявление D2, когда D1, по меньшей мере, столь же ограничено, как D2, а D2, по меньшей мере, не так ограничено, как D1.
Поскольку, <integral> wrapper
по крайней мере, оно не так ограничено <signed_integral> wrapper
, последнее считается более ограниченным, чем первое.
И поэтому, когда они оба могут подать заявку, побеждает более ограниченное объявление.
Имейте в виду, что правила подчинения ограничения прекращаются, когда встречается выражение, которое не является concept
. Так что, если вы сделали это:
template<typename T>
constexpr bool my_is_integral_v = std::is_integral_v<T>;
template<typename T>
concept my_signed_integral = my_is_integral_v<T> && std::is_signed_v<T>;
В этом случае my_signed_integral
не определили бы std::integral
. Хотя my_is_integral_v
определяется идентичноstd::is_integral_v
, что оно , поскольку это не концепция, правила подстановки в C ++ не могут просмотреть его, чтобы определить, что они одинаковы.
Таким образом, правила подчинения побуждают вас строить концепции из операций над атомарными концепциями.