C++ Writing Concepts
A concept is a named rule for a template. It states what a type must be able to do before the template accepts it.
One template accepts too much
The addScores template adds two values and works for ints. It would also accept strings, where adding joins the text end to end and means a different job.
#include <iostream>
template <typename T>
T addScores(T a, T b) {
return a + b;
}
int main() {
std::cout << addScores(40, 2) << std::endl;
std::cout << addScores(10, 5) << std::endl;
return 0;
}A concept guards the same function
The Addable concept asks for two valid expressions. The template now names Addable, so only types that pass can call it.
#include <iostream>
#include <concepts>
template <typename T>
concept Addable = requires(T a, T b) {
a + b;
a == b;
};
template <Addable T>
T addScores(T a, T b) {
return a + b;
}
int main() {
std::cout << addScores(40, 2) << std::endl;
std::cout << addScores(10, 5) << std::endl;
return 0;
}Two concepts combined with &&
The Printable concept asks that a value can be sent to std::cout. The combined concept demands both rules, and the function adds and prints.
#include <iostream>
#include <concepts>
template <typename T>
concept Addable = requires(T a, T b) {
a + b;
a == b;
};
template <typename T>
concept Printable = requires(T a) {
std::cout << a;
};
template <typename T>
concept AddableAndPrintable = Addable<T> && Printable<T>;
template <AddableAndPrintable T>
void addAndPrint(T a, T b) {
std::cout << a + b << std::endl;
}
int main() {
addAndPrint(2, 3);
addAndPrint(1.5, 2.5);
return 0;
}Example
#include <iostream>
#include <concepts>
#include <string>
#include <vector>
template <typename T>
concept HasSize = requires(T a) {
a.size();
};
template <HasSize T>
void printSize(T value) {
std::cout << value.size() << std::endl;
}
int main() {
std::vector<int> scores = {10, 20, 30};
printSize(scores);
std::string word = "hello";
printSize(word);
return 0;
}Key points
- An unconstrained template accepts any type at the call.
- The compiler only fails later, when the body cannot use that type.
- Use requires to list the expressions a type must support.
- A simple requirement checks that an expression is valid.
- A simple requirement does not fix the type of the result.
- Concepts combine with && when a type must meet two rules at once.
- A concept is written once and can guard many templates.
In this example, the HasSize concept asks for a size call on the value. The vector holds three scores, so printSize prints 3. The string holds five letters, so printSize prints 5.
Note
Programs that define concepts include the <concepts> header.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does the Addable concept check?