Узнайте о концепции в C++ 20

Узнайте о концепции в C++ 20 Программирование и разработка

Самая последняя версия C++ была выпущена в 2020 году как C++ 20. Она включает в себя несколько улучшений и новых функций, повышающих гибкость и возможности языка. В этом блоге будут рассмотрены некоторые из наиболее важных и ценных функций C++20 с примерами кода, которые могут быть полезны программистам.

В этом блоге мы будем обсуждать conceptразличные примеры.

concept

concept— это новая функция языка, представленная в C++20. Он определен в шапке. Он предоставляет способ определения требований к аргументам шаблона, что позволяет создавать более краткий и удобочитаемый код. Это достигается за счет предоставления программисту возможности указывать ограничения на параметры шаблона. Эти ограничения проверяются во время компиляции без ущерба для безопасности типов. Это помогает выявлять ошибки в шаблонном коде на ранних этапах цикла разработки, повышая надежность кода.

concept— это новая функция языка, представл

Как правило, признаки типа используются для обеспечения соответствия аргументов шаблона определенным требованиям. Однако признаки типа могут быть сложными для понимания и могут привести к многословному коду. Концепции позволяют определить эти требования непосредственно в списке параметров шаблона.

Определение concept

A conceptможно легко определить следующим образом:

template <typename T>
concept Integral = std::is_integral_v<T>;

Определение концепции интеграла

Приведенный выше код определяет Integralконцепцию, которая гарантирует, что Tтип параметра является целочисленным. Эту концепцию можно использовать для сложения двух чисел следующим образом:

template <Integral T>
T Add(T lhs, T rhs)
{
    return lhs + rhs;
}

Добавьте функцию, которая возвращает сумму двух чисел

Функция Addшаблона использует эту Integralконцепцию, чтобы гарантировать, что передаваемые параметры имеют целочисленный тип. Затем функция складывает два числа и возвращает их сумму.

int main()
{
/*
Integral Types are:
char , signed char , unsigned char -8 bits
short int , signed short int , and unsigned short int -16 bits
int , signed int , and unsigned int -32 bits
long int , signed long int , and unsigned long int -32 bits (OpenVMS)
long int , signed long int , and unsigned long int -64 bits (Digital UNIX)
signed __int64 (Alpha) and unsigned __int64 (Alpha)-64 bits
enum -32 bits
*/
    std::cout<<«The sum of two integers is «<< Add(10, 20)<<«\n»;
    std::cout<<«The sum of two 8 bit characters converted to ASCII is «<< Add(‘a’, ‘b’)<<«\n»;
    //Following line will generate an error as floating point is not an integral value.
//    std::cout<<«The sum of two doubles is «<< Add(10.2, 20.3)<<«\n»;
    return 0;
}

Основная для функции Add, демонстрирующая добавление интегральных типов

В строках 14–15 в приведенном выше коде сумма двух intи двух charбыла выполнена с использованием Addфункции. Код успешно сгенерирует правильный вывод, как показано ниже. Помните, что символы ASCII являются 8-битными, и будет переполнение.

Результат сложения двух целых чисел и двух 8-битных символов

Результат сложения двух целых чисел и двух 8-битных символов

Однако, если строка 17 раскомментирована, код выдаст ошибку времени компиляции, как показано ниже. Функция Addопределена для целых значений, но не для значений с плавающей запятой.

Ошибка времени компиляции при добавлении числа с плавающей запя

Ошибка времени компиляции при добавлении числа с плавающей запятой или двойного числа с помощью функции Add

Включая список ограничений

concept также может использоваться для включения списка ограничений. Это можно сделать с помощью requires. Следующий код определяет Stringконцепцию, которая требует, Tчтобы тип имел c_strфункцию-член, возвращающую файл const char *.

concept также может использоваться для включения списка огра

Функция print_stringшаблона определяется с помощью Stringконцепции. Важно отметить использование requiresв определении функции. Это гарантирует, что они Tбудут следовать Stringконцепции. Функция print_stringпечатает valueиспользование c_str()функции.

template <typename T>
concept String = requires(T s)
{
    { s.c_str() } -> std::convertible_to<const char*>;
};
template <typename T>
requires String<T>
void print_string(T value)
{
    std::cout << value.c_str();
}

Определение и использование концепции String

Пользовательские типы данных

Возьмем еще один пример, объясняющий, как концепция с +оператором работает с определенным типом. В этом коде requiresиспользуется для включения списка ограничений.

template <typename T>
concept Addable = requires(T x, T y)
{
    {x + y} -> std::convertible_to<T>;
};

Определение концепции Addable

В приведенном выше примере Addableконцепция требует двух объектов типа Tи помечена как requires. Выражение {x + y}должно быть допустимым оператором, а результат оператора может быть преобразован в тот же тип, Tчто xи y.

Используя эту Addableконцепцию, мы можем написать функцию, которая требует добавления аргументов.

template <Addable T>
T Sum(T a, T b)
{
    return a + b;
}

Функция Sum, которая требует добавления аргумента

В приведенном выше примере Sumфункция принимает два аргумента типа Tи требует, чтобы они Tудовлетворяли Addableконцепции. Это означает, что +оператор гарантированно доступен для аргументов, а функцию можно использовать с любым типом, удовлетворяющим концепции.

Следующий код использует концепцию и функцию, определенные выше, для вычисления суммы двух Rationalчисел.

struct Rational
{
    int Numerator;
    int Denominator;
    Rational operator+(const Rational & rhs)const
    {
        return {Numerator * rhs.Denominator + Denominator * rhs.Numerator, Denominator * rhs.Denominator};
    }
};
template <>
struct std::common_type<Rational>
{
    using type = Rational;
};
int main()
{
    Rational num1 {1, 2};
    Rational num2 {1, 3};
    Rational result = Sum (num1, num2);
    std::cout <<«The sum of two rational numbers is «<< result.Numerator <<«/»<< result.Denominator <<«\n»;
    // Output: The sum of two rational numbers is 5/6
    std::cout<<«The sum of two integers is «<< Sum(10, 20)<<«\n»;
    // Output: The sum of two integers is 30
    std::cout<<«The sum of two doubles is «<< Sum(10.5, 20.9)<<«\n»;
    // Output: The sum of two doubles is 31.4
    return 0;
}

Примеры использования концепции Addable

В строках 1—10Rational определен пользовательский тип, представляющий рациональное число. В структуре реализован оператор +в строках 6–9, удовлетворяющий требованиям концепции. AddableНаконец, std::common_typeбыла предоставлена ​​специализация, чтобы указать, что общий тип двух Rationalобъектов также Rational. В функции созданы и инициализированы mainдва объекта типа. RationalФункция Sumбыла вызвана с использованием этих двух объектов. Функция вызывает перегруженный +оператор и возвращает результат сложения, который сохраняется в другом resultобъекте и выводится на консоль. Более того, два примера примитивных типов данных intиdouble, также были предоставлены для уточнения использования concept. Поскольку concept оператор +был определен в этом примере, его conceptможно использовать для обеспечения доступности других операторов для разных типов данных.

Уточнение

Возьмем другой пример, где conceptможно использовать для уточнения. В следующем коде Rangeопределен a, для которого требуется тип Tдля реализации begin, и endфункции, возвращающие a iteratorтого же типа.

template <typename T>
concept Range = requires(T t)
{
    { t.begin() } -> std::same_as<typename T::iterator>;
    { t.end() } -> std::same_as<typename T::iterator>;
};
template <Range R>
void print_range(const R & lhs)
{
    for(auto it = lhs.begin(); it != lhs.end(); it++)
        std::cout << *it << » «;
}

Концепция может быть использована для уточнения

Функция print_rangeв строках 9–13 реализует Rangeконцепцию печати всего содержимого контейнера, начиная с первого и заканчивая последним элементом.

int main() {
    // Initializing a vector with C++20 initializer syntax
    std::vector<int> vec{ 1, 2, 3, 4, 5 };
    print_range(vec);
    //Output: 1 2 3 4 5
    //int array[] = {1,2,3,4,5};
    //print_range(array);
    // Compile-time error: no matching function for call to ‘print_range(int [5])’
    return 0;
}

Печать вектора с помощью print_range

В строке 3 a vectorбыл определен и инициализирован. В строке 4print_range была вызвана функция для печати файла vector. Выход по желанию. Однако, когда строки 6–7 раскомментированы, во время компиляции генерируется ошибка, указывающая на то, что для массива не существует соответствующей функции, intпоскольку у него нет функций beginи. endЭто предотвращает любую ошибку времени выполнения, которая могла привести к прекращению выполнения.

Заключение

Короче говоря, conceptобеспечивает более удобный для чтения и поддержки способ определения ограничений на параметры шаблона. Это упрощает выражение требований аргумента шаблона и написание универсального кода, который работает с широким диапазоном типов.

Читайте также:  Как поменять местами две строки в массиве NumPy?
Оцените статью
bestprogrammer.ru
Добавить комментарий