Концепция — интерфейсное расширение шаблонов языка C++, опубликованное в технической спецификации ИСО/МЭК ISO TS 19217:2015. По своей сути концепция является набором логических предикатов, размещённых за списком параметров шаблона, которые оцениваются во время компиляции исходного кода с целью установления ограничений на свойства аргументов, которые принимаются в качестве параметров шаблона.
Введение концепций связывают с дальнейшим развитием в языке C++ инструментария, основанного на парадигме обобщённого программирования. Концепция может быть объявлена с шаблоном любого вида (класс-шаблон, шаблон-функция, или функция-член класса-шаблона), её назначением является выявление логических несоответствий между свойствами типов данных, которые используются внутри тела шаблона и свойствами типов данных, которые поступают в шаблон в качестве входных параметров.
До введения в стандарт языка понятие концепции было реализовано в библиотеке общего назначения Boost в виде библиотечных классов проверки концепций BCCL ().
Синтаксис текущего предложения (из Си++20) Определение концепции.
template <class T> concept EqualityComparable() { requires(T a, T b) { {a == b} -> Boolean; // Концепция, означающая тип, преобразуемый в boolean {a != b} -> Boolean; -> boost::asio:;system::error_code&
Шаблон, использующий концепцию (обратите внимание, нет ключевого слова template).
void f(const EqualityComparable auto&);
Концепции будут участвовать в выборе, какую функцию из набора перегруженных применять, наряду с SFINAE. Компилятор предпочтёт самую «жёсткую» концепцию.
Если использовать концепцию в инициализаторе, это будет аналог auto, однако код будет компилироваться, если концепция поддерживается. Sortable auto x = f(y); // аналог auto x = f(y), компилируется, если результат — тип, подходящий под Sortable
Предпосылки В обобщённом программировании концепция — это такой набор требований к типу, чтобы шаблон обобщённого программирования имел смысл. Например, шаблон It2 std::copy(It1, It1, It2) предполагает такие соотношения между типами-итераторами It1 и It2. It1 и It2 — однонаправленные итераторы. Между типами *It2 и *It1 возможно присваивание.
Эти концепции описаны в документации по Си++, и они — словесное описание условий, когда код компилируется. Так, при попытке специализировать шаблон с параметрами It1=int*, It2=int** компилятор сообщит, что невозможно присваивание int* ← int. При этом есть недостатки. Ошибка выпадет в глубине заголовочного файла STL — в сложном заведомо правильном коде. Зачастую тексты ошибок крайне многословны, и сложно выяснить, чего именно не хватает, чтобы шаблон специализировался. Когда программист пишет шаблон, он может случайно выйти из концепции и не заметить это. Это никак нельзя проверить, кроме как попытавшись специализировать шаблон. На сложных шаблонах «проверка специализацией» не так проста, как кажется — большинство простейших типов поддерживают много лишних функций. Так, недостаточно проверить std::vector<T> на типе int: помимо операций «конструктор без параметров», «конструктор перемещения» и «присвоить с перемещением», минимально требуемых для вектора, у целого типа есть конструктор копирования, операция присваивания, математические операции и многое другое, и нет гарантий, что они не используются.
Кроме того, приходится делать функции, которые появляются или исчезают в зависимости от некоторых условий (соответствия или несоответствия концепции). В Си++17 шаблоны для этого сложны.
По сей день синтаксически описать концепции получилось только ограниченно — так, в Java роль концепций играют утверждения наподобие class Test <T extends Testable>.
Текущее состояние Компилятор Частично Полностью G++ 6 10 MSVC 2019 2022 Clang 10 10
Примечания
Категория:Шаблоны C++