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