C++ concepts
Sep 11, 2025I implemented a templated class in C++. One of its methods had an equality check, which made me wonder how C++ handled the fact that my generic type T might not support the == operator.
Let’s consider the following class to illustrate:
template <typename T> class A {
public:
A(T v) { value = v; }
bool is(T v) { return value == v; }
private:
T value;
};
You see the equality check value == v there. But v can be of any type. How does C++ handle that? Is there a way of enforcing that T must support ==?
So let’s consider the following struct Foo:
struct Foo {
std::string s;
};
So, the program below compiles just fine.
int main()
{
A<Foo> foo1 = Foo{"Hello"};
return 0;
}
Which is weird because we know that if we call foo1.is the program will likely break.
Let’s call foo1.is, then:
int main()
{
A<Foo> foo1 = Foo{"Hello"};
std::cout << foo1.is(Foo{"Hello"}) << "\n";
return 0;
}
Now the program fails to compile:
main.cpp: In instantiation of ‘bool A<T>::is(T) [with T = Foo]’:
main.cpp:35:25: required from here
main.cpp:20:20: error: no match for ‘operator==’ (operand types are ‘Foo’ and ‘Foo’)
20 | return value == v;
| ~~~~~~^~~~
So, it is only when we call the function that executes the unsupported operation that the compiler complains. I wondered if there was a way to enforce this requirement at the time of object instantiation, and there is.
C++20 introduced concepts, a way of specifying requirements explicitly. We can add the concept std::equality_comparable to our template:
#include <concepts>
template <std::equality_comparable T>
class A {
public:
A(T v) {
value = v;
}
bool is(T v) {
return value == v;
}
private:
T value;
};
and we get a compilation error at the instantiation:
main.cpp: In function ‘int main()’:
main.cpp:35:10: error: template constraint failure for ‘template requires equality_comparable class A’
35 | A<Foo> foo1 = Foo{"Hello"};
| ^
main.cpp:35:10: note: constraints not satisfied
If we now add support for the == operator in Foo, the program compiles:
struct Foo {
std::string s;
bool operator==(const Foo& other) const {
return s == other.s;
}
};