C++

⭐ Maßtrise totale

Métaprogrammation (Templates avancés)

La métaprogrammation template permet d'effectuer des calculs au moment de la compilation.

Calcul Ă  la compilation

#include <iostream> // Factorielle Ă  la compilation template <int N> struct Factorielle { static constexpr int valeur = N * Factorielle<N - 1>::valeur; }; template <> struct Factorielle<0> { static constexpr int valeur = 1; }; // Fibonacci Ă  la compilation template <int N> struct Fibonacci { static constexpr int valeur = Fibonacci<N-1>::valeur + Fibonacci<N-2>::valeur; }; template <> struct Fibonacci<0> { static constexpr int valeur = 0; }; template <> struct Fibonacci<1> { static constexpr int valeur = 1; }; int main() { std::cout << "5! = " << Factorielle<5>::valeur << std::endl; // 120 std::cout << "Fib(10) = " << Fibonacci<10>::valeur << std::endl; // 55 return 0; }

SFINAE et enable_if

#include <iostream> #include <type_traits> // Fonction pour les types entiers template <typename T> typename std::enable_if<std::is_integral<T>::value, void>::type traiter(T valeur) { std::cout << "Type entier: " << valeur << std::endl; } // Fonction pour les types Ă  virgule flottante template <typename T> typename std::enable_if<std::is_floating_point<T>::value, void>::type traiter(T valeur) { std::cout << "Type flottant: " << valeur << std::endl; } int main() { traiter(42); // Type entier traiter(3.14); // Type flottant return 0; }

Concepts C++20

#include <iostream> #include <concepts> // Définir un concept template <typename T> concept Numerique = std::is_arithmetic_v<T>; // Utiliser un concept template <Numerique T> T multiplier(T a, T b) { return a * b; } // Concept personnalisé template <typename T> concept AMethodePrint = requires(T t) { { t.print() } -> std::same_as<void>; }; template <AMethodePrint T> void afficher(const T& obj) { obj.print(); } int main() { std::cout << multiplier(5, 3) << std::endl; std::cout << multiplier(2.5, 4.0) << std::endl; return 0; }

Variadic Templates

#include <iostream> // Fonction récursive pour afficher des arguments void afficher() { std::cout << std::endl; } template <typename Premier, typename... Reste> void afficher(Premier premier, Reste... reste) { std::cout << premier << " "; afficher(reste...); } // Somme variadic template <typename... Args> auto somme(Args... args) { return (args + ...); // Fold expression C++17 } int main() { afficher(1, 2.5, "Hello", 'x', true); std::cout << "Somme: " << somme(1, 2, 3, 4, 5) << std::endl; return 0; }

Optimisation et performance

constexpr avancé

#include <iostream> #include <array> // Fonction constexpr constexpr int fibonacci(int n) { if (n <= 1) return n; return fibonacci(n-1) + fibonacci(n-2); } // Classe constexpr class Rectangle { private: int largeur, hauteur; public: constexpr Rectangle(int l, int h) : largeur(l), hauteur(h) {} constexpr int aire() const { return largeur * hauteur; } }; int main() { // Calculé à la compilation constexpr int fib10 = fibonacci(10); constexpr Rectangle rect(10, 20); constexpr int aire = rect.aire(); std::cout << "Fibonacci(10): " << fib10 << std::endl; std::cout << "Aire: " << aire << std::endl; return 0; }

Cache-friendly code

#include <iostream> #include <vector> #include <chrono> // Structure of Arrays (SoA) - Plus cache-friendly struct Particules_SoA { std::vector<float> x; std::vector<float> y; std::vector<float> z; std::vector<float> masse; void reserve(size_t n) { x.reserve(n); y.reserve(n); z.reserve(n); masse.reserve(n); } }; // Array of Structures (AoS) - Moins cache-friendly pour certaines opĂ©rations struct Particule { float x, y, z, masse; }; void traiterSoA(Particules_SoA& p) { // AccĂšs sĂ©quentiel au mĂȘme champ = bon pour le cache for (size_t i = 0; i < p.x.size(); i++) { p.x[i] *= 2.0f; } }

Coroutines C++20

#include <iostream> #include <coroutine> // Générateur simple struct Generator { struct promise_type { int current_value; Generator get_return_object() { return Generator{std::coroutine_handle<promise_type>::from_promise(*this)}; } std::suspend_always initial_suspend() { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_void() {} void unhandled_exception() {} std::suspend_always yield_value(int value) { current_value = value; return {}; } }; std::coroutine_handle<promise_type> handle; Generator(std::coroutine_handle<promise_type> h) : handle(h) {} ~Generator() { if (handle) handle.destroy(); } bool next() { handle.resume(); return !handle.done(); } int value() { return handle.promise().current_value; } }; Generator compteur(int debut, int fin) { for (int i = debut; i < fin; i++) { co_yield i; } } int main() { auto gen = compteur(1, 6); while (gen.next()) { std::cout << gen.value() << " "; } return 0; }

Memory Management avancé

Allocateurs personnalisés

#include <iostream> #include <memory> #include <vector> template <typename T> class MonAllocateur { public: using value_type = T; MonAllocateur() noexcept {} template <typename U> MonAllocateur(const MonAllocateur<U>&) noexcept {} T* allocate(std::size_t n) { std::cout << "Allocation de " << n << " éléments" << std::endl; return static_cast<T*>(::operator new(n * sizeof(T))); } void deallocate(T* p, std::size_t n) noexcept { std::cout << "Libération de " << n << " éléments" << std::endl; ::operator delete(p); } }; int main() { std::vector<int, MonAllocateur<int>> vec; vec.push_back(1); vec.push_back(2); vec.push_back(3); return 0; }

Memory Pool

#include <iostream> #include <vector> #include <cstddef> class MemoryPool { private: std::vector<char> pool; size_t offset; public: MemoryPool(size_t taille) : pool(taille), offset(0) {} void* allouer(size_t taille) { if (offset + taille > pool.size()) { return nullptr; // Pool plein } void* ptr = &pool[offset]; offset += taille; return ptr; } void reset() { offset = 0; } }; int main() { MemoryPool pool(1024); int* a = static_cast<int*>(pool.allouer(sizeof(int))); int* b = static_cast<int*>(pool.allouer(sizeof(int))); *a = 42; *b = 100; std::cout << *a << ", " << *b << std::endl; return 0; }

Design Patterns en C++

Singleton thread-safe

#include <iostream> #include <mutex> class Singleton { private: static Singleton* instance; static std::mutex mtx; Singleton() {} // Constructeur privé public: Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; static Singleton* getInstance() { if (instance == nullptr) { std::lock_guard<std::mutex> lock(mtx); if (instance == nullptr) { instance = new Singleton(); } } return instance; } void afficher() { std::cout << "Instance Singleton" << std::endl; } }; // C++11 approche plus simple (thread-safe automatiquement) class SingletonModerne { private: SingletonModerne() {} public: static SingletonModerne& getInstance() { static SingletonModerne instance; return instance; } SingletonModerne(const SingletonModerne&) = delete; void operator=(const SingletonModerne&) = delete; };

Observer Pattern

#include <iostream> #include <vector> #include <memory> class Observer { public: virtual ~Observer() = default; virtual void update(int valeur) = 0; }; class Subject { private: std::vector<std::weak_ptr<Observer>> observers; int etat; public: void attacher(std::shared_ptr<Observer> obs) { observers.push_back(obs); } void setEtat(int nouvelEtat) { etat = nouvelEtat; notifier(); } void notifier() { for (auto it = observers.begin(); it != observers.end();) { if (auto obs = it->lock()) { obs->update(etat); ++it; } else { it = observers.erase(it); } } } }; class ObserverConcret : public Observer { private: std::string nom; public: ObserverConcret(std::string n) : nom(n) {} void update(int valeur) override { std::cout << nom << " a reçu: " << valeur << std::endl; } };

Projets avancés suggérés

  1. Créer un moteur de jeu 2D avec ECS (Entity Component System)
  2. Implémenter un allocateur mémoire personnalisé haute performance
  3. Développer une bibliothÚque de calcul vectoriel avec SIMD
  4. Créer un framework de tests unitaires complet
  5. Implémenter un compilateur pour un mini-langage
  6. Développer un serveur HTTP asynchrone avec coroutines