MareArts ANPR mobile app

12/12/2025

Why Can't We Use Functions in "requires"? #04_why_not_both.cpp

 

.

// Example 4: Why Can't We Use Functions in "requires"?
// This shows the difference between concepts and constexpr functions

#include <iostream>
#include <concepts>

// ==========================================
// Define types
// ==========================================

struct Dog {
const char* name = "MareArts.com";
};

struct Cat {
const char* name = "Whiskers";
};

// ==========================================
// METHOD 1: Using CONCEPT (works in requires)
// ==========================================

template <typename T>
concept HasName = requires(T t) {
{ t.name } -> std::convertible_to<const char*>;
};

template <typename T>
requires HasName<T> // ✅ Works! Concept in requires clause
void printNameWithConcept(T animal) {
std::cout << "Name: " << animal.name << "\n";
}

// ==========================================
// METHOD 2: Using CONSTEXPR FUNCTION (doesn't work in requires!)
// ==========================================

template <typename T>
consteval bool hasNameFunction() {
return requires(T t) {
{ t.name } -> std::convertible_to<const char*>;
};
}

// ❌ This won't compile!
// template <typename T>
// requires hasNameFunction<T>() // ❌ ERROR: Can't use function in requires!
// void printNameWithFunction(T animal) {
// std::cout << "Name: " << animal.name << "\n";
// }

// ==========================================
// METHOD 3: Using CONSTEXPR FUNCTION with "if constexpr" (works!)
// ==========================================

template <typename T>
void printNameIfConstexpr(T animal) {
// ✅ Works! Function in "if constexpr"
if constexpr (hasNameFunction<T>()) {
std::cout << "Name: " << animal.name << "\n";
}
else {
std::cout << "No name!\n";
}
}

// ==========================================
// WHY THE DIFFERENCE?
// ==========================================

/*
"requires" clause:
- Part of template declaration
- Needs a CONCEPT (compile-time constraint)
- Determines if template can even exist
- Syntax: template <...> requires CONCEPT<T>

"if constexpr":
- Inside function body
- Can use ANY compile-time expression
- Chooses which code branch to keep
- Syntax: if constexpr (EXPRESSION)
*/

// ==========================================
// Main
// ==========================================

int main() {
Dog dog;
Cat cat;
std::cout << "=== Using Concept in 'requires' ===\n";
printNameWithConcept(dog);
printNameWithConcept(cat);
std::cout << "\n=== Using Function in 'if constexpr' ===\n";
printNameIfConstexpr(dog);
printNameIfConstexpr(cat);
return 0;
}

/*
SUMMARY - Where Can You Use What?

┌──────────────────────────┬──────────────┬──────────────────┐
│ │ "requires" │ "if constexpr" │
├──────────────────────────┼──────────────┼──────────────────┤
│ Concept │ ✅ │ ✅ │
│ Constexpr Function │ ❌ │ ✅ │
│ Any compile-time expr │ ❌ │ ✅ │
└──────────────────────────┴──────────────┴──────────────────┘

This is why:
- Factories use concepts in "requires" (IsReferenceAlgorithm concept)
- Dispatcher uses constexpr functions in "if constexpr" (IsReferenceAlgorithm())

After refactoring:
- We removed the concept (not needed anymore)
- Kept the constexpr function (used in dispatcher)
- Removed algorithm checks from factory "requires" clauses
*/


..


.

### 4. Why Not Both? (04_why_not_both.cpp)
**What it teaches:** Why we can't mix them up

```
┌──────────────────────────┬──────────────┬──────────────────┐
│ │ "requires" │ "if constexpr" │
├──────────────────────────┼──────────────┼──────────────────┤
│ Concept │ ✅ │ ✅ │
│ Constexpr Function │ ❌ │ ✅ │
└──────────────────────────┴──────────────┴──────────────────┘
```

**Key Point:** Constexpr functions DON'T work in `requires` clauses!

..

Now #1~#4 series is done.

g++ -std=c++20 01_concept_basics.cpp -o 01_concepts
g++ -std=c++20 02_constexpr_functions.cpp -o 02_constexpr
g++ -std=c++20 03_dispatcher_pattern.cpp -o 03_dispatcher
g++ -std=c++20 04_why_not_both.cpp -o 04_why


recap!

## Key Takeaways 🎯

1. **Concepts** check if types have certain features
- Used in `requires` clauses
- Like: `requires HasName<T>`

2. **Constexpr functions** run at compile time
- Used in `if constexpr` statements
- Like: `if constexpr (isDog<T>())`

3. **Dispatcher pattern** separates concerns:
- **Dispatcher** checks algorithm type (using `if constexpr` + constexpr functions)
- **Factory** checks direction only (using `requires` + concepts)

4. **You can't mix them:**
- Constexpr functions DON'T work in `requires` clauses
- That's why we removed the algorithm check from factory `requires` clauses!


Thank you!

study.marearts.com


No comments:

Post a Comment