Skip to content

CPP 15. Ограничения накладываемые на шаблоны. Требования к шаблонам (requires). Концепты. Типы ограничений. Варианты определения шаблонов функций и классов с концептами.

Dmitriy Pisarenko edited this page Jun 15, 2023 · 2 revisions

Требования к шаблонам (requires)

Если есть функции, которые выполняют одни и те же действия, но для разных типов данных, то их можно шаблонизировать.

В С надо либо плодить однотипные функции, что плохо по определению, либо использовать макросы с параметрами, что опасно, так как подстановка идет на этапе компиляции, а проверка - на этапе выполнения.

В С++ эта проблема решается шаблонами.

Шаблоны решают проблему дублирования кода

Шаблон может быть для функции, класса, метода класса, своего типа. Во время компиляции будет подстановка параметров шаблона с проверкой шаблона.

Шаблон не является ни классом, ни функцией. Функция и класс генерируется на основе шаблона во время использования.

Компилятор встречает вызов шаблона функции (создание класса) - смотрит, может ли он быть использован и если может, то по шаблону создается функция(класс).

Начиная со стандарта С++20 в язык был добавлен оператор requires, который позволяет установить для параметров шаблонов ограничения.

template <параметры> requires ограничения
содержимое шаблона;

Ограничения представляют условные выражения, которые возвращают значение типа bool - если параметр типа удовлетворяет условию, то возвращается true. Каждое ограничение предписывает одно или несколько требований для одного или нескольких параметров шаблона.

Например, мы хотим определить функцию, которая может складывать числа:

#include <iostream>
 
template <typename T> requires std::is_same<T, int>::value || std::is_same<T, double>::value
T sum(T a, T b){ return a + b;}
 
int main()
{
    std::cout << sum(3, 4) << std::endl;
    std::cout << sum(12.5, 4.3) << std::endl;
    //std::cout << sum(5l, 7l) << std::endl;
}

Здесь определен шаблон функции sum, который принимает значения типа T и возвращает их сумму также в виде значения типа T. Для параметра T после слова requires установлено ограничение

std::is_same<T, int>::value || std::is_same<T, double>::value Для определения ограничения применяется встроенная структура std::is_same из стандартной библиотеки C++. Эта структура в свою очередь типизируется двумя типами. Переменная value структуры возвращает true, если оба типа одинаковы. То есть выражение std::is_same<T, int>::value возвратит true, если T - это int. Аналогично устанавливаем еще одно ограничение к типу - std::is_same<T, double>::value. И с помощью операции || объединяем два ограничения. То есть T может представлять либо int, либо double.

Далее мы можем передавать в функцию sum() значения типов, которые удовлетворяют этим ограничениям:

std::cout << sum(3, 4) << std::endl;        // передаем int
std::cout << sum(12.5, 4.3) << std::endl;   // передаем double

Значения других же типов мы передать не можем. Так, в примере выше закомментирована строка, где в функцию sum() передаются значения типа long:

//std::cout << sum(5l, 7l) << std::endl;  // long работать не будет

Если мы ее раскомментируем, то компилятор не скомпилирует программу и отобразит нам ошибку, которая сообщит, что в функцию sum переданы значения некорректных типов.

Концепты

template <typename T>
concept size = sizeof(T) <= sizeof(int);

В данном случае определен концепт size. Его смысл в том, что тип, который будет передаваться через параметр T, должен удовлетворять условию sizeof(T) <= sizeof(int). То есть физический размер объектов типа T не должен быть больше размера значений типа int.

Ограничения накладываемые на шаблоны

Мы можем применять концепты в качестве ограничений для шаблонов

#include <iostream>
 
template <typename T>
concept size = sizeof(T) <= sizeof(int);
 
template <typename T> requires size<T> // в качестве ограничения применяется size
T sum(T a, T b){ return a + b;}
 
int main()
{
    std::cout << sum(10, 3) << std::endl;       // 13
    //std::cout << sum(10.6, 3.7) << std::endl; // ! Ошибка
}

Сокращенный синтаксис

template <size T> // в качестве ограничения применяется size
T sum(T a, T b){ return a + b;}

Типы ограничений - ?

Варианты определения шаблонов функций и классов с концептами. - ?

Clone this wiki locally