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.