C++ concept Keyword

The concept keyword in C++ was introduced in C++20 to define constraints on template parameters. A concept specifies requirements for template arguments, such as supported operations, type traits, or valid expressions. It makes generic programming more robust by ensuring that only valid types can be used with a template, providing clearer error messages during compilation.

Concepts improve readability, enforce type safety, and reduce template instantiation errors. They are essential for modern C++ programming and simplify working with templates by explicitly declaring the requirements for template parameters.


Syntax

</>
Copy
template <typename T>
concept ConceptName = constraint_expression;
template<typename T>
Defines a template parameter T for the concept.
ConceptName
The name of the concept being defined.
constraint_expression
An expression that specifies the requirements for the concept. It can include type traits, valid operations, or expressions.

Examples

Example 1: Basic Concept for Arithmetic Types

This example defines a concept that ensures a type supports arithmetic operations like addition and subtraction.

</>
Copy
#include <iostream>
#include <concepts>

// Define a concept for arithmetic types
template <typename T>
concept Arithmetic = std::is_arithmetic_v<T>;

// Function template using the concept
template <Arithmetic T>
T add(T a, T b) {
    return a + b;
}

int main() {
    std::cout << "Sum: " << add(10, 20) << std::endl; // Valid
    // Uncommenting the following line will cause a compile-time error
    // std::cout << add(std::string("Hello"), std::string("World")) << std::endl;
    return 0;
}

Output:

Sum: 30

Explanation:

  1. The concept Arithmetic uses std::is_arithmetic_v<T> to check if the type T supports arithmetic operations.
  2. The add function template requires its parameter type T to satisfy the Arithmetic concept.
  3. In main, integers satisfy the Arithmetic concept, so the addition operation is valid.
  4. Attempting to use non-arithmetic types (e.g., std::string) results in a clear compile-time error.

Example 2: Concept for Containers

This example defines a concept to constrain types to standard containers that provide begin() and end() methods.

</>
Copy
#include <iostream>
#include <vector>
#include <list>
#include <concepts>

// Define a concept for containers
template <typename T>
concept Container = requires(T c) {
    c.begin(); // Must have a begin() method
    c.end();   // Must have an end() method
};

// Function template using the concept
template <Container T>
void printContainer(const T& container) {
    for (const auto& element : container) {
        std::cout << element << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::vector<int> vec = {1, 2, 3};
    std::list<int> lst = {4, 5, 6};

    printContainer(vec); // Valid
    printContainer(lst); // Valid

    // Uncommenting the following line will cause a compile-time error
    // printContainer(5); // Not a container

    return 0;
}

Output:

1 2 3
4 5 6

Explanation:

  1. The concept Container checks if a type has begin() and end() methods, which are common for standard containers.
  2. The printContainer function template is constrained to types satisfying the Container concept.
  3. std::vector and std::list satisfy the Container concept, so their elements are printed.
  4. Passing a non-container type results in a compile-time error with a clear diagnostic message.

Key Points about concept Keyword

  1. The concept keyword is used to define compile-time constraints for template parameters.
  2. Concepts simplify template programming by providing clear, concise requirements for template arguments.
  3. They improve error diagnostics and help prevent template instantiation errors.
  4. Concepts can validate types, operations, and expressions during compilation.
  5. Using concepts requires a C++20-compatible compiler and enabling the C++20 standard.