MareArts ANPR mobile app

12/12/2025

C++ concept basics #01_concept_basic.cpp

 

**What it teaches:** C++ Concepts are like "type requirements"

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

// Use in requires clause
template <typename T>
requires HasName<T> // ✅ Concept works here!
void printName(T animal) {
std::cout << animal.name;
}
```

**Key Point:** Concepts work in `requires` clauses

..

#include <iostream>
#include <concepts>

// ==========================================
// CONCEPT: Checks if a type has certain features
// ==========================================

// Simple concept: checks if type T has a "name" member
template <typename T>
concept HasName = requires(T t) {
{ t.name } -> std::convertible_to<const char*>;
};

// Another concept: checks if type T has a "bark()" method
template <typename T>
concept CanBark = requires(T t) {
{ t.bark() } -> std::same_as<void>;
};

// ==========================================
// Types that satisfy concepts
// ==========================================

struct Dog {
const char* name = "marearts.com Rex";
void bark() { std::cout << "Woof!\n"; }
};

struct Cat {
const char* name = "marearts.com Whiskers";
// No bark() method!
};

struct Robot {
// No name field!
void bark() { std::cout << "Beep boop!\n"; }
};

// ==========================================
// Functions that use concepts in "requires"
// ==========================================

// This function ONLY accepts types that have a name
template <typename T>
requires HasName<T> // ← Concept used in requires clause
void printName(T animal) {
std::cout << "Name: " << animal.name << "\n";
}

// This function ONLY accepts types that can bark
template <typename T>
requires CanBark<T> // ← Concept used in requires clause
void makeBark(T animal) {
animal.bark();
}

// ==========================================
// Main - Try it out!
// ==========================================

int main() {
Dog dog;
Cat cat;
Robot robot;
std::cout << "=== Using Concepts in 'requires' ===\n";
// ✅ Works - Dog has name
printName(dog);
// ✅ Works - Cat has name
printName(cat);
// ❌ Won't compile - Robot doesn't have name
// printName(robot); // Uncomment to see error!
std::cout << "\n";
// ✅ Works - Dog can bark
makeBark(dog);
// ❌ Won't compile - Cat can't bark
// makeBark(cat); // Uncomment to see error!
// ✅ Works - Robot can bark
makeBark(robot);
return 0;
}

..

How to build and run?

--------------------------------------------------------------------------------------------

>g++ -std=c++20 01_concept_basics.cpp -o 01_concept_basics

>./01_concept_basics

=== Using Concepts in 'requires' ===

Name: Rex

Name: Whiskers


Woof!

Beep boop!

--------------------------------------------------------------------------------------------


What is convertible_ to and same_as??

Used in your HasName concept:
01_concept_basics.cppLines 13-15
This checks that t.name returns something that can be converted to const char*. It's more flexible than requiring an exact type match - so it would accept const char*char*, or any type convertible to const char*.

std::same_as

Used in your CanBark concept:
01_concept_basics.cppLines 19-21
This checks that t.bark() returns exactly void - no conversions allowed. It's stricter than convertible_to.

And there are more predefined concepts?

These are C++20 Standard Concepts

Both are defined in the C++20 standard library <concepts> header. Other common standard concepts include:
  • std::integral<T> - checks if T is an integral type
  • std::floating_point<T> - checks if T is a floating point type
  • std::derived_from<Derived, Base> - checks inheritance
  • std::invocable<F, Args...> - checks if F can be called with Args
You can create your own concepts (like you did with HasName and CanBark), or use these predefined ones from the standard library! 🎯


Thank you!

MareArts



No comments:

Post a Comment