O C ++ 20 possui um mecanismo para decidir quando uma entidade restrita específica é "mais restrita" que outra. Isso não é uma coisa simples.
Isso começa com o conceito de quebrar uma restrição em seus componentes atômicos, um processo chamado normalização de restrição . É grande e muito complexo para abordar aqui, mas a idéia básica é que cada expressão em uma restrição seja dividida em suas partes conceituais atômicas, recursivamente, até que você atinja uma sub-expressão componente que não é um conceito.
Portanto, vejamos como os conceitos integral
e são definidos :signed_integral
template<class T>
concept integral = is_integral_v<T>;
template<class T>
concept signed_integral = integral<T> && is_signed_v<T>;
A decomposição de integral
é justa is_integral_v
. A decomposição de signed_integral
é is_integral_v && is_signed_v
.
Agora, chegamos ao conceito de subsunção de restrição . É meio complicado, mas a idéia básica é que se diz que uma restrição C1 "subsume" uma restrição C2 se a decomposição de C1 contiver todas as subexpressões em C2. Podemos ver que integral
não subsume signed_integral
, mas signed_integral
faz subsumir integral
, uma vez que contém tudo o que integral
faz.
Em seguida, passamos a ordenar entidades restritas:
Uma declaração D1 é pelo menos tão restrita quanto uma declaração D2 se * D1 e D2 são ambas declarações restritas e as restrições associadas a D1 se sobrepõem às de D2; ou * D2 não possui restrições associadas.
Como signed_integral
subsume integral
, o <signed_integral> wrapper
é "pelo menos tão restrito" quanto o <integral> wrapper
. No entanto, o inverso não é verdadeiro, porque a subsunção não é reversível.
Portanto, de acordo com a regra para entidades "mais restritas":
Uma declaração D1 é mais restrita que outra declaração D2 quando D1 é pelo menos tão restrita quanto D2 e D2 não é pelo menos tão restrita quanto D1.
Como o <integral> wrapper
não é pelo menos tão restrito quanto <signed_integral> wrapper
, o último é considerado mais restrito que o anterior.
E, portanto, quando os dois puderam se candidatar, a declaração mais restrita vence.
Esteja ciente de que as regras de subsunção de restrição param quando uma expressão é encontrada que não é a concept
. Então, se você fez isso:
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>;
Nesse caso, my_signed_integral
não iria desaparecer std::integral
. Embora my_is_integral_v
seja definido de forma idêntica std::is_integral_v
, por não ser um conceito, as regras de subsunção do C ++ não podem examiná-lo para determinar se são iguais.
Portanto, as regras de subsunção encorajam você a construir conceitos fora das operações em conceitos atômicos.