C ++ 20 имеет механизм для принятия решения, когда одна конкретная ограниченная сущность «более ограничена», чем другая. Это не простая вещь.
Это начинается с концепции разбиения ограничения на его атомарные c компоненты, процесс, называемый нормализация ограничений . Он большой и слишком сложный для go, но основная идея c заключается в том, что каждое выражение в ограничении разбивается на его атомарные c концептуальные части, рекурсивно, пока вы не достигнете под-выражения компонента, которое не является это не концепция.
Итак, давайте посмотрим, как определяются понятия 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
.
Теперь мы подошли к понятию ограничение подчинения . Это довольно сложно, но основная идея c состоит в том, что ограничение 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
последний считается более ограниченным, чем первый.
И, следовательно, когда оба они могут применяться, побеждает более ограниченное объявление.
Помните, что правила ограничение подстановки stop при обнаружении выражения, которое не является 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 ++ не могут просмотреть его, чтобы определить, что они одинаковы.
Таким образом, правила подстановки побуждают вас строить понятия из операций над атомами c понятия.