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