C++ Concepts

Type constraints and template requirements made simple

🎯 What are C++ Concepts?

C++ Concepts define requirements for template parameters, making templates safer and error messages clearer. They specify what types can be used with templates, improving code readability and debugging experience.


// Simple concept example
#include <concepts>

template<typename T>
concept Addable = requires(T a, T b) {
    a + b;
};

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

Usage:

int result = add(5, 3); // Works - int supports +

// add("hello", "world"); // Error - clear message

Key Concept Features

âś…

Type Safety

Ensure types meet requirements

template<std::integral T>
void process(T value) { }
📝

Clear Errors

Better compiler error messages

// Clear: "T must be integral"
// Instead of template gibberish
🔍

Requirements

Express what operations are needed

concept Printable = requires(T t) {
    std::cout << t;
};
🎨

Readability

Self-documenting template code

template<Sortable Container>
void sort_data(Container& c);

🔹 Basic Concept Definition

The concept keyword in C++20 enables the definition of named compile‑time predicates for template parameters. Concepts specify requirements that types must satisfy, improving template readability and error messages. For example, a Sortable concept ensures types support comparison and swapping. This enhances code clarity and allows compilers to enforce constraints early, reducing cryptic template errors and facilitating better documentation of generic interfaces.

#include <concepts>

// Simple concept - checks if type has + operator
template<typename T>
concept Addable = requires(T a, T b) {
    a + b;  // Must support addition
};

// Using the concept
template<Addable T>
T sum(T x, T y) {
    return x + y;
}

int main() {
    int result1 = sum(10, 20);        // âś… Works
    double result2 = sum(1.5, 2.5);   // âś… Works
    // sum(std::vector{1}, std::vector{2}); // ❌ Error
    return 0;
}

Output:

result1 = 30

result2 = 4.0

🔹 Standard Library Concepts

C++20’s standard library includes predefined concepts like std::integral and std::floating_point. These built‑in concepts cover common type requirements, reducing boilerplate. For instance, std::integral<int> evaluates to true, enabling templates to restrict parameters to integer families. Utilizing these concepts accelerates development and ensures consistency with the language’s type‑traits system.

#include <concepts>
#include <iostream>

// Using standard concepts
template<std::integral T>
void print_integer(T value) {
    std::cout << "Integer: " << value << std::endl;
}

template<std::floating_point T>
void print_float(T value) {
    std::cout << "Float: " << value << std::endl;
}

int main() {
    print_integer(42);      // âś… int is integral
    print_float(3.14);      // âś… double is floating_point
    // print_integer(3.14); // ❌ Error - clear message
    return 0;
}

Output:

Integer: 42

Float: 3.14

🔹 Complex Requirements

Concepts can combine multiple requirements using logical operators like && and ||. This allows expressing sophisticated constraints, such as a type being both copyable and comparable. Complex concepts enable precise API specifications, ensuring that templates only accept types meeting all necessary operations, which enhances safety and reduces runtime checks.

#include <concepts>
#include <iostream>

// Complex concept with multiple requirements
template<typename T>
concept Printable = requires(T t) {
    std::cout << t;           // Must be printable
    { t.size() } -> std::integral;  // Must have size() returning integral
};

template<Printable T>
void print_with_size(const T& item) {
    std::cout << "Item: " << item 
              << " (size: " << item.size() << ")" << std::endl;
}

int main() {
    std::string text = "Hello";
    std::vector<int> numbers = {1, 2, 3};
    
    print_with_size(text);     // âś… Works
    print_with_size(numbers);  // âś… Works
    // print_with_size(42);    // ❌ Error - no size()
    return 0;
}

Output:

Item: Hello (size: 5)

Item: [vector content] (size: 3)

đź§  Test Your Knowledge

What keyword is used to define a concept in C++20?