Наступна інформація застаріла. Його потрібно оновити відповідно до останнього проекту Concepts Lite.
Розділ 3 пропозиції щодо обмежень висвітлює це досить поглиблено.
Пропозиція концепцій була ненадовго виставлена на задній план з надією, що обмеження (тобто поняття-lite) можуть бути розроблені та впроваджені за коротший часовий проміжок, в даний час націлений хоча б на щось у C ++ 14. Пропозиція обмежень покликана діяти як плавний перехід до більш пізнього визначення понять. Обмеження є частиною пропозиції концепцій і є необхідним будівельним елементом у її визначенні.
В розробці концептуальних бібліотек для C ++ , Саттон і Страуструп враховують такі взаємозв'язки:
Поняття = Обмеження + Аксіоми
Щоб швидко підсумувати їх значення:
- Обмеження - предикат над статично оцінюваними властивостями типу. Суто синтаксичні вимоги. Не абстракція домену.
- Аксіоми - семантичні вимоги типів, які вважаються істинними. Не перевірено статично.
- Поняття - загальні, абстрактні вимоги алгоритмів до їх аргументів. Визначається з точки зору обмежень та аксіом.
Отже, якщо ви додасте аксіоми (семантичні властивості) до обмежень (синтаксичні властивості), ви отримаєте поняття.
Поняття-Lite
Пропозиція концепцій-lite пропонує нам лише першу частину, обмеження, але це важливий і необхідний крок до повноцінних концепцій.
Обмеження
Обмеження стосуються синтаксису . Вони дають нам спосіб статично розрізнити властивості типу під час компіляції, щоб ми могли обмежити типи, що використовуються як аргументи шаблону, виходячи з їх синтаксичних властивостей. У поточній пропозиції щодо обмежень вони виражаються підмножиною пропозиційного числення, використовуючи логічні сполучники типу&&
та ||
.
Давайте подивимось на обмеження в дії:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
Тут ми визначаємо шаблон функції, який називається sort
. Нове доповнення - це застереження . Речення require надає деякі обмеження щодо аргументів шаблону для цієї функції. Зокрема, це обмеження говорить, що тип Cont
повинен бути Sortable
типом. Акуратно те, що це можна записати в більш стислій формі як:
template <Sortable Cont>
void sort(Cont& container);
Тепер, якщо ви спробуєте передати Sortable
цій функції будь-що, що не враховується , ви отримаєте приємну помилку, яка одразу повідомляє, що тип, виведений для T
, не є Sortable
типом. Якби ви зробили це в C ++ 11, у вас виникла б жахлива помилка зсередини в sort
функції , яка не має ніякого сенсу нікому.
Предикати обмежень дуже схожі на ознаки типу. Вони беруть певний тип аргументу шаблону і дають вам деяку інформацію про нього. Обмеження намагаються відповісти на такі типи запитань про тип:
- Чи є у цього типу перевантажений такий-то оператор?
- Чи можна використовувати ці типи як операнди цього оператора?
- Чи є у цього типу такі-то риси?
- Чи дорівнює цей постійний вираз цьому? (для нетипових аргументів шаблону)
- Чи має цей тип функцію під назвою yada-yada, яка повертає цей тип?
- Чи відповідає цей тип усім синтаксичним вимогам, які слід використовувати як такі?
Однак обмеження не покликані замінити риси типу. Натомість вони працюватимуть рука об руку. Деякі риси типу тепер можна визначити з точки зору понять, а деякі поняття - з точки зору типів.
Приклади
Тож головне у обмеженнях полягає в тому, що вони не дбають про семантику на йоту. Деякі хороші приклади обмежень:
Equality_comparable<T>
: Перевіряє, чи тип має ==
обидва операнди того самого типу.
Equality_comparable<T,U>
: Перевіряє, чи є ==
лівий та правий операнди заданих типів
Arithmetic<T>
: Перевіряє, чи тип арифметичний.
Floating_point<T>
: Перевіряє, чи тип має тип із плаваючою комою.
Input_iterator<T>
: Перевіряє, чи підтримує тип синтаксичні операції, які повинен підтримувати ітератор введення.
Same<T,U>
: Перевіряє, чи вказаний тип однаковий.
Ви можете спробувати все це за допомогою спеціальної концепції-полегшеної збірки GCC .
Поза концепціями-Lite
Тепер ми потрапляємо у все, що виходить за рамки концептуальної пропозиції. Це навіть більш футуристично, ніж саме майбутнє. Все з цього моменту, ймовірно, зміниться зовсім небагато.
Аксіоми
Аксіоми стосуються семантики . Вони визначають відносини, інваріанти, гарантії складності та інші подібні речі. Давайте розглянемо приклад.
Незважаючи на те, що Equality_comparable<T,U>
обмеження повідомляє вам, що існує тип, operator==
який приймає типи T
і U
, він не говорить вам, що означає ця операція . Для цього ми матимемо аксіому Equivalence_relation
. Ця аксіома говорить, що коли об’єкти цих двох типів порівнюють із operator==
даванням true
, ці об’єкти еквівалентні. Це може здатися зайвим, але, звичайно, ні. Ви можете легко визначити an, operator==
який замість цього поводився якoperator<
. Ви були б злі робити це, але могли б.
Інший приклад - Greater
аксіома. Це все добре , щоб сказати два об'єкти типу T
можна порівняти з >
і <
оператори, але що вони означають ? Greater
Аксіома каже , що тоді і тільки тоді x
, більше тоді y
, то y
менше x
. Запропонована специфікація такої аксіоми виглядає так:
template<typename T>
axiom Greater(T x, T y) {
(x>y) == (y<x);
}
Тож аксіоми відповідають на такі типи запитань:
- Чи мають ці два оператори такі взаємини між собою?
- Чи означає це цей оператор для такого-то типу?
- Чи має ця операція над цим типом таку складність?
- Чи означає цей результат цього оператора, що це правда?
Тобто їх цілком стосується семантика типів та операцій над цими типами. Ці речі не можна перевірити статично. Якщо це потрібно перевірити, тип повинен якимось чином проголосити, що він дотримується цієї семантики.
Приклади
Ось кілька типових прикладів аксіом:
Equivalence_relation
: Якщо два об'єкти порівнюються ==
, вони еквівалентні.
Greater
: Коли завгодно x > y
, тоді y < x
.
Less_equal
: Коли завгодно x <= y
, тоді !(y < x)
.
Copy_equality
: For x
і y
від типу T
: if x == y
, новий об’єкт того ж типу, створений шляхом побудови копії T{x} == y
і досі x == y
(тобто він не руйнує).
Поняття
Зараз поняття дуже легко визначити; вони просто поєднання обмежень та аксіом . Вони забезпечують абстрактні вимоги щодо синтаксису та семантики типу.
Як приклад розглянемо таку Ordered
концепцію:
concept Ordered<Regular T> {
requires constraint Less<T>;
requires axiom Strict_total_order<less<T>, T>;
requires axiom Greater<T>;
requires axiom Less_equal<T>;
requires axiom Greater_equal<T>;
}
Спочатку зауважимо, що для того, T
щоб тип шаблону був Ordered
, він також повинен відповідати вимогам Regular
концепції. Regular
Концепція дуже основні вимоги , що тип є добре себе - він може бути побудований, зруйнований, копіюються і порівнюються.
На додаток до цих вимог, вимоги, Ordered
що T
відповідають одному обмеженню та чотирьом аксіомам:
- Обмеження:
Ordered
Тип повинен мати operator<
. Це перевірено статично, тому воно повинно існувати.
- Аксіоми: Для
x
і y
від типу T
:
x < y
дає суворе тотальне впорядкування.
- Коли
x
більше y
, y
менше x
, і навпаки.
- Коли
x
менше або дорівнює y
, y
не менше x
, і навпаки.
- Коли
x
більше або дорівнює y
, y
не більше x
і навпаки.
Поєднання таких обмежень та аксіом дає вам поняття. Вони визначають синтаксичні та семантичні вимоги до абстрактних типів для використання з алгоритмами. В даний час алгоритми повинні припускати, що використовувані типи будуть підтримувати певні операції та виражати певну семантику. Завдяки концепціям ми зможемо переконатися, що вимоги виконуються.
В останньому дизайні концепцій компілятор перевірятиме лише, що синтаксичні вимоги концепції виконуються аргументом шаблону. Аксіоми не позначено. Оскільки аксіоми позначають семантику, яка не піддається статистичній оцінці (або часто неможливо повністю перевірити), автор типу повинен чітко вказати, що їх тип відповідає всім вимогам концепції. Це було відоме як відображення концепції в попередніх проектах, але з тих пір було видалено.
Приклади
Ось кілька прикладів понять:
Regular
типи можна сконструювати, зруйнувати, скопіювати і їх можна порівняти.
Ordered
підтримують типи operator<
та мають сувору тотальну впорядкування та іншу семантику впорядкування.
Copyable
типи є копіюваними, які можна конструювати, руйнувати, і якщо x
дорівнює y
і x
копіюється, копія також буде порівнюватися рівним y
.
Iterator
типи повинні бути пов'язані типи value_type
, reference
, difference_type
, і iterator_category
які самі по собі повинні відповідати певним поняттям. Вони також повинні підтримувати operator++
та бути недоступними для перегляду.
Шлях до концепцій
Обмеження - це перший крок до повноцінної концепції C ++. Вони є дуже важливим кроком, оскільки вони забезпечують статично забезпечені вимоги типів, щоб ми могли писати набагато чистіші функції та класи шаблонів. Тепер ми можемо уникнути деяких труднощів і потворності std::enable_if
та їх метапрограмування друзів.
Однак є ряд речей, яких пропозиція обмежень не робить:
Він не забезпечує мову визначення поняття.
Обмеження не є концептуальними картами. Користувачеві не потрібно спеціально коментувати свої типи як відповідність певним обмеженням. Вони статично перевіряються за допомогою простих мов мов компіляції.
Реалізації шаблонів не обмежуються обмеженнями на їх аргументи шаблонів. Тобто, якщо ваш шаблон функції робить щось із об’єктом обмеженого типу, чого не повинен робити, компілятор не має можливості діагностувати це. Повнофункціональна пропозиція щодо концепцій могла б це зробити.
Пропозиція обмежень була розроблена спеціально для того, щоб на неї можна було ввести повну концепцію пропозицій. Якщо пощастить, цей перехід повинен бути досить плавним. Група концепцій прагне ввести обмеження для C ++ 14 (або в технічному звіті незабаром після цього), тоді як повні концепції можуть почати з'являтися десь близько C ++ 17.