Constraints and Concepts in C++ 20
Last Updated :
24 Apr, 2025
In this article, we will learn about the constraints and concepts with the help of examples in a simple way. So, it is a feature that was introduced in the latest version i.e. C++20 that specifies requirements on template arguments and enables more expressive and readable code.
What are Constraints in C++?
Constraints are the conditions or requirements that need to be satisfied by template arguments when using templates. It allows the user to specify what types or values can be used with a template.
Types of Constraints
1. Conjunctions
It combines multiple constraints using AND (&) operator. It specifies that all the constraints within the conjunction must be satisfied for the overall constraint to be satisfied.
template <typename T>
requires Constraint1 && Constraint2 && ... && ConstraintN
void functionName(T parameter) {
// Function body
}
2. Disjunctions
It is used to combine multiple constraints with the help of the OR (||) operator. It specifies that at least one of the constraints within the disjunction must be satisfied for the overall constraint to be satisfied.
template <typename T>
requires Constraint1 || Constraint2 || ... || ConstraintN
void functionName(T parameter) {
// Function body
}
3. Atomic constraints
They are individual constraints that define specific requirements on types, expressions, or template arguments.
template <typename T>
concept ConceptName = Constraint1 && Constraint2 && ... && ConstraintN;
template <typename T>
requires ConceptName<T>
void functionName(T parameter) {
// Function body
}
Examples of Constraints
Example 1:
The below code demonstrates the usage of constraints in C++ to restrict the valid types that can be used with function templates.
C++
// C++ program to illustrate the constrains
#include <iostream>
#include <type_traits>
using namespace std;
// Function template with constraint using requires clause
template <typename T>
requires is_integral_v<T> void print_integer(T value)
{
cout << "The integer value is: " << value << endl;
}
// Concept definition
template <typename T> concept Printable = requires(T value)
{
cout << value << endl;
};
// Function template with concept as a constraint
template <Printable T> void print(T value)
{
cout << "The printable value is: " << value << endl;
}
int main()
{
// Call the print_integer function with an integer
// argument
print_integer(42);
// Call the print function with a string argument
print("Hello, World!");
}
Output
The integer value is: 42
The printable value is: Hello, World!
Violations of constraints are typically detected during the template instantiation process in C++. The compiler generates an error message for the specific constraint that has been violated.
Example 2:
C++
// C++ program to illustrate the voilation in specified
// constrains for template arguments
#include <concepts>
#include <iostream>
template <typename T> requires integral<T> void foo(T value)
{
cout << "Value: " << value << endl;
}
int main()
{
// Valid usage, T = int (integral type)
foo(5);
// Error: Violation of constraint, T = double
// (not an integral type)
foo(3.14);
return 0;
}
Output
 What are Concepts in C++?
Concepts are used to specify the requirements of the template arguments. Concepts allow you to define constraints to your template. It is a way using which we can specify some constraints for our template arguments in C++.
Syntax
template <typename T>
concept ConceptName = /* constraints or requirements */;
If we combine these two terms then we can say that constraints are the expression and concepts is a way to define these expressions.
Examples of Concepts in C++
Example 1:
The below code demonstrates the usage of concepts in C++ to define and apply requirements on template arguments.
C++
// C++ Program to illustrate the use of concept to define
// constraints
#include <iostream>
#include <iterator>
#include <type_traits>
#include <vector>
using namespace std;
// Define the Container concept
template <typename T> concept Container = requires(T t)
{
{
std::size(t)
}
->std::same_as<std::size_t>;
{
std::begin(t)
}
->std::same_as<typename T::iterator>;
{
std::end(t)
}
->std::same_as<typename T::iterator>;
};
// Define the ContainerWrapper class that works with
// containers satisfying the
// Container concept
template <Container C> class ContainerWrapper {
public:
ContainerWrapper(C c)
: container(c)
{
}
// Print the elements of the container
void print()
{
for (auto it = std::begin(container);
it != std::end(container); ++it) {
cout << *it << " ";
}
cout << endl;
}
private:
C container;
};
int main()
{
// Create a vector container
vector<int> v{ 1, 2, 3 };
// Instantiate a ContainerWrapper object with the vector
ContainerWrapper wrapper(v);
// Print the elements of the container using the
// ContainerWrapper
wrapper.print();
}
Output
1 2 3
Note: Concepts in C++ can not refer to themselves in a recursive manner.
Example 2:
The below code demonstrates errors that occur when we define recursive concepts.
C++
template <typename T>
// Attempting recursive reference
concept RecursiveConcept = RecursiveConcept<T*>;
template <typename T>
void foo(T value) requires RecursiveConcept<T>
{
// Code
}
int main()
{
// Will result in a compiler error
foo(42);
return 0;
}
The above code will result in an error as we have defined a concept RecursiveConcept in the code that refers to itself that is not allowed in C++.
Concepts can be named in an id-expression. When we use the concept in an id-expression, the value of the id-expression is determined by whether the constraint expression of the concept is satisfied by the template argument.
If the constraint expression is satisfied by the template argument, the value of the id-expression is true, else it is false.
Conclusion
Constraints and concepts in C++ provide a powerful mechanism for expressing requirements on template arguments. It helps us to avoid the unwanted argument values for our templates. One thing to keep in mind is that constraints are the expression and concepts is a way to define these expressions.
Similar Reads
Code- Scheduling Constraints
Data dependence analysis is used to determine the order of execution of instructions. It is used to determine the order of execution of instructions because it gives an indication of how much effort will be required for a particular instruction to be executed at any given time. A data-dependent inst
9 min read
constinit Specifier in C++ 20
The constinit specifier is a new feature that is introduced in C++ 20 that allows us to declare a variable with static storage duration. In this article we will discuss the constinit specifier, its usage, advantages, and limitations. What is constinit Specifier? The constinit specifier is used to ma
3 min read
Argument Coercion in C/C++
Argument coercion is a feature of function prototypes by which the compiler implicitly converts the datatype of the arguments passed during the function call to match the datatype in the definition of the function. It follows Argument promotion rules. Therefore a lower datatype maybe converted into
1 min read
C++ Interview Questions and Answers (2025)
C++ - the must-known and all-time favourite programming language of coders. It is still relevant as it was in the mid-80s. As a general-purpose and object-oriented programming language is extensively employed mostly every time during coding. As a result, some job roles demand individuals be fluent i
15+ min read
C++ Programming and STL Facts
C++ is widely used for competitive programming. It is preferred because of its reliability, efficient execution, short snippets, etc. It has become adaptive by most coders as it also provides the benefits of Standard Template Library(STL). C++ STL is the backbone of programming. The inbuilt functio
5 min read
Containership in C++
We can create an object of one class into another and that object will be a member of the class. This type of relationship between classes is known as containership or has_a relationship as one class contain the object of another class. And the class which contains the object and members of another
5 min read
Can a constructor be private in C++ ?
Prerequisite : Constructors A constructor is a special member function of a class which initializes objects of a class. In C++, constructor is automatically called when object of a class is created. By default, constructors are defined in public section of class. So, question is can a constructor be
3 min read
Naming Convention in C++
Naming a file or a variable is the first and the very basic step that a programmer takes to write clean codes, where naming has to be appropriate so that for any other programmer it acts as an easy way to read the code. In C++, naming conventions are the set of rules for choosing the valid name for
6 min read
Friend Class and Function in C++
In C++, friend functions and friend classes are concepts that allow certain functions or classes to access the private and protected members of another class. These are useful concepts in such situations where you need to give a function or another class access to internal data, while still keeping
6 min read
Importance of Constructors in C++
Constructors are special member functions in C++ that are invoked automatically when an object of a class is created. Their primary role is to initialize objects. In this article, we will learn all the factors that makes the constructor important in C++. Table of Content Initialization of ObjectsRes
8 min read