Метапрограммирование — это техника написания программ, которые генерируют или манипулируют другими программами (или самими собой) во время компиляции. В C++ это позволяет выполнять вычисления и принимать решения на этапе компиляции, что приводит к более эффективному runtime-коду.
Базовый механизм метапрограммирования в C++:
template<int N>
struct Factorial {
static const int value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> {
static const int value = 1;
};
// Использование:
int x = Factorial<5>::value; // 120 (вычисляется на этапе компиляции)
Позволяют проверять свойства типов:
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
process(T value) {
// Реализация только для целочисленных типов
}
Вычисления во время компиляции:
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
int arr[factorial(5)]; // Массив размером 120
Условная компиляция:
template<typename T>
auto process(T value) {
if constexpr (std::is_pointer_v<T>) {
return *value;
} else {
return value;
}
}
Современный способ ограничения шаблонов:
template<typename T>
concept Arithmetic = std::is_integral_v<T> || std::is_floating_point_v<T>;
template<Arithmetic T>
T square(T x) {
return x * x;
}
template<int... Is>
struct IndexSequence {};
template<int N, int... Is>
struct MakeIndexSequence : MakeIndexSequence<N-1, N-1, Is...> {};
template<int... Is>
struct MakeIndexSequence<0, Is...> : IndexSequence<Is...> {};
// Использование для распаковки кортежа:
template<typename... Ts, int... Is>
void unpackTuple(const std::tuple<Ts...>& t, IndexSequence<Is...>) {
process(std::get<Is>(t)...);
}
template<bool UseSIMD>
void processData(float* data, size_t size) {
if constexpr (UseSIMD) {
// Векторизованная реализация
} else {
// Скалярная реализация
}
}
template<typename Impl>
class Interface {
public:
void execute() {
static_cast<Impl*>(this)->implementation();
}
};
class Concrete : public Interface<Concrete> {
public:
void implementation() {
// Реализация
}
};
Метапрограммирование в C++ позволяет:
Основные инструменты:
Используйте метапрограммирование там, где оно действительно дает преимущества, но помните о балансе между производительностью и поддерживаемостью кода.