Metaprogramming is a broad and complicated concept. There are several thick books talking about it, for example, “C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond”. I see it as a template programming tool that helps transfer some run-time work to compile time.
Below is a toy example of metaprogramming, a for-loop on compile time to print variable types. To see how it is interpreted on the compiler side, copy the code below to https://cppinsights.io/ and set the version to C++ 20 (It must be C++ 20 and after because the older versions use enable if instead of requires).
#include <tuple>
#include <memory>
#include <type_traits>
#include <iostream>
#include <iomanip>
template<typename TypeToPrint>
void printType(TypeToPrint&& t) {
std::cout << typeid(t).name() << std::endl;
}
template<typename... TypesToPrint>
void printType(TypesToPrint&&... ts) {
(printType(ts), ...);
}
// for loop base case
template<size_t I = 0, typename... TypesToPrint>
requires (I == sizeof...(TypesToPrint))
void printTypeNew(const std::tuple<TypesToPrint...>&) {}
// for loop reduction
template<size_t I = 0, typename... TypesToPrint>
requires (I < sizeof...(TypesToPrint))
void printTypeNew(const std::tuple<TypesToPrint...>& ts) {
printType(get<I>(ts));
printTypeNew<I + 1, TypesToPrint...>(ts);
}
template <typename... Types>
struct Tuple {
std::tuple<Types...> t;
void printAllTypes() const {
std::apply([](auto&&... ts){ printType(ts...); }, t);
}
void printAllTypesNew() const {
printTypeNew(t);
}
};
int main() {
Tuple<int*, std::unique_ptr<float>> T2;
T2.printAllTypes();
std::cout << "New way" << std::endl;
T2.printAllTypesNew();
}