Ch16: Concepts¶
TL;DR: Template Constraints: Concepts (C++20) constrain template parameters in function signatures, replacing type traits and
static_assertwith readable compile-time checks.
โก Quick Reference¶
#include <iostream>
#include <concepts>
#include <type_traits>
// Custom concept declaration using standard traits
template <typename T>
concept MyConcept = std::is_integral_v<T>;
// Custom concept utilizing a requires expression
template <typename T>
concept Addable = requires(T a, T b) {
a + b; // Simple requirement: checks syntactic validity
};
// Nested and compound requirement concepts
template <typename T>
concept TinyAndConvertible = requires(T a) {
requires sizeof(T) <= 4; // Nested requirement: evaluates boolean condition to true
{ a + 1 } -> std::convertible_to<int>; // Compound requirement: checks syntax & convertible return type
};
// Syntax 1: requires clause after template declaration
template <typename T>
requires std::integral<T>
T add1(T a, T b) { return a + b; }
// Syntax 2: Replace typename directly in template parameter list
template <std::integral T>
T add2(T a, T b) { return a + b; }
// Syntax 3: Constrained auto parameter
auto add3(std::integral auto a, std::integral auto b) { return a + b; }
// Syntax 4: Trailing requires clause
template <typename T>
T add4(T a, T b) requires std::integral<T> { return a + b; }
// Combining concepts using logic OR / AND
template <typename T>
requires std::integral<T> || std::floating_point<T>
void print_num(T val) {
// Constrains auto variable declarations
std::integral auto copy = val;
}
int main() {
return 0;
}
๐ง Core Concepts¶
- Template Constraints: Concepts (C++20) constrain template parameters in function signatures, replacing type traits and
static_assertwith readable compile-time checks. - Requirements Clauses: Custom concepts enforce criteria using simple (syntactic check), nested (boolean check), and compound (syntactic and return-type checks) requirements inside
requiresclauses. - Flexible Syntaxes: Concepts can constrain parameters via parameter-list replacements (
template<concept T>), trailingrequiresclauses, or prefixedautovariables.
โ ๏ธ Pitfalls (Quick Scan)¶
| Mistake | Fix |
|---|---|
Using a simple requirement (e.g., sizeof(T) <= 4) for boolean assertions |
Wrap boolean expression checks inside a nested requires statement |
Forgetting that operations (like char addition) trigger implicit promotion to int |
Use explicit return values or cast expression outcomes to match expected template constraints |
Assuming syntactic operations in concepts (like a b) check logic/semantics |
Combine syntactic checks with type trait validation to verify semantic meaning |
Declaring complex concepts inline inside requires clauses |
Define named concepts separately and reference them by name in template signatures |
| Relying solely on IDE squiggly lines for debugging concept errors | Compile code with GCC to receive descriptive outputs specifying exactly which constraints failed |
๐ Full Details¶
Cause โ Effect โ Fix with timestamp (click to expand)
* **Using a simple requirement (e.g., `sizeof(T) <= 4`) for boolean assertions** -> **Compiler only checks if the expression is syntactically valid C++, ignoring the boolean result and incorrectly accepting large types** -> **Wrap boolean expression checks inside a nested `requires` statement (13:58)** * **Forgetting that operations (like `char` addition) trigger implicit promotion to `int`** -> **Concept-constrained return types fail constraints if the promoted type violates size limitations** -> **Use explicit return values or cast expression outcomes to match expected template constraints (18:50)** * **Assuming syntactic operations in concepts (like `a * b`) check logic/semantics** -> **Operations are accepted if they compile, regardless of whether the semantics make mathematical sense** -> **Combine syntactic checks with type trait validation to verify semantic meaning (09:35)** * **Declaring complex concepts inline inside `requires` clauses** -> **Function signatures become cluttered, ugly, and extremely difficult to read** -> **Define named concepts separately and reference them by name in template signatures (26:10)** * **Relying solely on IDE squiggly lines for debugging concept errors** -> **Diagnostic messages are often generic and fail to isolate the violated sub-constraint** -> **Compile code with GCC to receive descriptive outputs specifying exactly which constraints failed (05:30)**๐ Repo Files¶
25.02UsingConcepts/main.cpp25.03BuildingYourOwnConcepts/main.cpp25.04ZoomingInOnRequiresClause/main.cpp25.05CombiningConcepts/main.cpp25.06ConceptsAndAuto/main.cpp