La métaprogrammation template permet d'effectuer des calculs au moment de 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;
}#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;
}#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;
}#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;
}#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;
}#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;
}
}#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;
}#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;
}#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;
}#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;
};#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;
}
};