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 ++ не могут просмотреть его, чтобы определить, что они одинаковы.
Таким образом, правила подчинения побуждают вас строить концепции из операций над атомарными концепциями.