0 day streak
cpp / expert
Snippet

Constraining Class Templates with C++20 Concepts

Using C++20 concept declarations to constrain class templates enforces strict type requirements at compile-time with clear error messages. Instead of unconstrained templates or complex SFINAE, concepts establish explicit interface contracts for template arguments, adhering to clean architecture best practices.

snippet.cpp
cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <concepts>
#include <string>
template <typename T>
concept Serialisable = requires(const T& obj) {
{ obj.serialize() } -> std::same_as<std::string>;
};
template <Serialisable T>
class DataExporter {
public:
explicit DataExporter(T data) : data_(std::move(data)) {}
void export_data() const {
std::cout << "Exporting payload: " << data_.serialize() << '\n';
}
private:
T data_;
};
struct UserRecord {
std::string name;
std::string serialize() const { return "UserRecord{name: " + name + "}"; }
};
int main() {
UserRecord user{"Alice"};
DataExporter<UserRecord> exporter(user);
exporter.export_data();
}
Breakdown
1
concept Serialisable = requires(const T& obj)
Defines compile-time predicate verifying serialize() returning std::string.
2
template <Serialisable T> class DataExporter
Constrains the template class parameter directly at definition site.
3
DataExporter<UserRecord> exporter(user);
Instantiates class template validated against concept contract.