C ++ 20 ma mechanizm decydujący, kiedy jeden konkretny ograniczony podmiot jest „bardziej ograniczony” niż inny. To nie jest prosta sprawa.
Zaczyna się od koncepcji rozbicia wiązania na jego komponenty atomowe, procesu zwanego normalizacją wiązania . Jest tu zbyt duży i zbyt skomplikowany, aby go tu wchodzić, ale podstawową ideą jest to, że każde wyrażenie w ograniczeniu jest rekurencyjnie dzielone na atomowe elementy pojęciowe, aż do osiągnięcia podwyrażenia składowego, które nie jest pojęciem.
Biorąc to pod uwagę, spójrzmy jak zdefiniowane są pojęcia integral
i :signed_integral
template<class T>
concept integral = is_integral_v<T>;
template<class T>
concept signed_integral = integral<T> && is_signed_v<T>;
Rozkład integral
jest sprawiedliwy is_integral_v
. Rozkład signed_integral
jest is_integral_v && is_signed_v
.
Teraz dochodzimy do koncepcji subsumcji ograniczeń . Jest to trochę skomplikowane, ale podstawową ideą jest to, że ograniczenie C1 mówi się, że „przejmuje” ograniczenie C2, jeśli rozkład C1 zawiera każde podwyrażenie w C2. Widzimy, że integral
to nie ulega zniszczeniu signed_integral
, ale signed_integral
się zmniejsza integral
, ponieważ zawiera wszystko, co integral
robi.
Następnie przechodzimy do zamawiania podmiotów z ograniczeniami:
Deklaracja D1 jest co najmniej tak ograniczona jak deklaracja D2, jeśli * D1 i D2 są zarówno ograniczonymi deklaracjami, a powiązane ograniczenia D1 obejmują te z D2; lub * D2 nie ma powiązanych ograniczeń.
Ponieważ signed_integral
obejmuje integral
, <signed_integral> wrapper
jest „co najmniej tak samo ograniczony” jak <integral> wrapper
. Jednak sytuacja odwrotna nie jest prawdą, ponieważ subskrypcja nie jest odwracalna.
Dlatego zgodnie z zasadą dla „bardziej ograniczonych” podmiotów:
Deklaracja D1 jest bardziej ograniczona niż inna deklaracja D2, gdy D1 jest co najmniej tak samo ograniczona jak D2, a D2 nie jest co najmniej tak ograniczona jak D1.
Ponieważ <integral> wrapper
to nie jest co najmniej tak ograniczone jak to <signed_integral> wrapper
, drugie jest uważane za bardziej ograniczone niż pierwsze.
A zatem, gdy obaj mogą się ubiegać, wygrywa deklaracja bardziej ograniczona.
Należy pamiętać, że reguły subsumcji ograniczeń kończą się, gdy napotkamy wyrażenie, które nie jest a concept
. Więc jeśli to zrobiłeś:
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>;
W takim przypadku my_signed_integral
nie wziąłby udziału std::integral
. Mimo że my_is_integral_v
jest zdefiniowane identycznie std::is_integral_v
, ponieważ nie jest to pojęcie, reguły subskrypcji C ++ nie mogą przejrzeć go w celu ustalenia, że są takie same.
Reguły subskrypcji zachęcają więc do budowania pojęć z operacji na pojęciach atomowych.