Toy Metaprogramming

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();
}