C ++ 20 a un mécanisme pour décider quand une entité contrainte particulière est "plus contrainte" qu'une autre. Ce n'est pas simple.
Cela commence par le concept de décomposer une contrainte en ses composants atomiques, un processus appelé normalisation des contraintes . C'est grand et trop complexe pour être abordé ici, mais l'idée de base est que chaque expression dans une contrainte est décomposée en ses pièces conceptuelles atomiques, récursivement, jusqu'à ce que vous atteigniez une sous-expression de composant qui n'est pas un concept.
Donc, étant donné cela, regardons comment les concepts integral
et sont définis :signed_integral
template<class T>
concept integral = is_integral_v<T>;
template<class T>
concept signed_integral = integral<T> && is_signed_v<T>;
La décomposition de integral
est juste is_integral_v
. La décomposition de signed_integral
is is_integral_v && is_signed_v
.
Nous arrivons maintenant au concept de subsomption de contraintes . C'est un peu compliqué, mais l'idée de base est qu'une contrainte C1 est censée «subsumer» une contrainte C2 si la décomposition de C1 contient chaque sous-expression dans C2. Nous pouvons voir que integral
ne subsume pas signed_integral
, mais signed_integral
ne subsumer integral
, car il contient tout integral
fait.
Ensuite, nous arrivons à classer les entités contraintes:
Une déclaration D1 est au moins aussi contrainte qu'une déclaration D2 si * D1 et D2 sont tous deux des déclarations contraintes et les contraintes associées de D1 subsument celles de D2; ou * D2 n'a pas de contraintes associées.
Parce que signed_integral
subsume integral
, le <signed_integral> wrapper
est "au moins aussi contraint" que le <integral> wrapper
. Cependant, l'inverse n'est pas vrai, car la subsomption n'est pas réversible.
Par conséquent, conformément à la règle pour les entités "plus contraintes":
Une déclaration D1 est plus contrainte qu'une autre déclaration D2 lorsque D1 est au moins aussi contraint que D2, et D2 n'est pas au moins aussi contraint que D1.
Étant donné que le <integral> wrapper
n'est pas au moins aussi contraint que <signed_integral> wrapper
, ce dernier est considéré comme plus contraint que le premier.
Et donc, lorsque les deux pourraient s'appliquer tous les deux, la déclaration la plus contrainte l'emporte.
Sachez que les règles de subsomption de contraintes s'arrêtent lorsqu'une expression est rencontrée qui n'est pas a concept
. Donc, si vous avez fait ça:
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>;
Dans ce cas, my_signed_integral
ne subsume passtd::integral
. Même s'il my_is_integral_v
est défini de manière identique à std::is_integral_v
, car il ne s'agit pas d'un concept, les règles de subsomption de C ++ ne peuvent pas le parcourir pour déterminer qu'elles sont identiques.
Les règles de subsomption vous encouragent donc à construire des concepts à partir d'opérations sur des concepts atomiques.