Следующая информация устарела. Его необходимо обновить в соответствии с последним проектом Concepts Lite.
Раздел 3 предложения по ограничениям рассматривает это достаточно подробно.
Предложение по концепциям было отложено на некоторое время в долгий ящик в надежде, что ограничения (например, концепции-lite) могут быть конкретизированы и реализованы в более короткие сроки, в настоящее время стремясь хотя бы к чему-то в C ++ 14. Предложение ограничений разработано, чтобы действовать как плавный переход к более позднему определению понятий. Ограничения являются частью концептуального предложения и необходимым строительным блоком в его определении.
При разработке концептуальных библиотек для C ++ Саттон и Страуструп рассматривают следующие отношения:
Концепции = Ограничения + Аксиомы
Чтобы быстро резюмировать их значения:
- Ограничение - предикат над статически оцениваемыми свойствами типа. Чисто синтаксические требования. Не абстракция домена.
- Аксиомы - семантические требования к типам, которые считаются истинными. Статически не проверено.
- Понятия - общие, абстрактные требования алгоритмов к своим аргументам. Определен в терминах ограничений и аксиом.
Итак, если вы добавите аксиомы (семантические свойства) к ограничениям (синтаксические свойства), вы получите концепции.
Концепты-Lite
Предложение по упрощенным концепциям приносит нам только первую часть, ограничения, но это важный и необходимый шаг на пути к полноценным концепциям.
Ограничения
Все ограничения связаны с синтаксисом . Они дают нам возможность статически различать свойства типа во время компиляции, так что мы можем ограничить типы, используемые в качестве аргументов шаблона, на основе их синтаксических свойств. В текущем предложении ограничений они выражаются с помощью подмножества исчисления высказываний с использованием логических связок, таких как &&
и ||
.
Давайте посмотрим на ограничение в действии:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
Здесь мы определяем шаблон функции с именем sort
. Новое дополнение - это предложение required . Предложение requires дает некоторые ограничения на аргументы шаблона для этой функции. В частности, это ограничение говорит о том, что тип 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
, эти объекты эквивалентны. Это может показаться излишним, но это определенно не так. Вы можете легко определить, 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
and y
of type 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.