Search code examples
c++templatesmetaprogramming

How to print std::tuple iteratively


Most samples of c++ books leverage recursively mechanism to print std::tuple. Is it possible to print std::tuples iteratively by leverage sizeof...(Typename)?

For example, the function signature is like below:

template<typename... Ts> constexpr void PrintTuple(std::tuple<Ts...>& tuple)

Then I could use sizeof...(Ts) to know how many elements in the tuple and then I could use std::get< i >(tuple) to retrieve the individual element?


Solution

  • Here's one of the possible solutions:

    #include <cstddef>
    #include <iostream>
    #include <tuple>
    #include <type_traits>
    #include <utility>
    
    template <typename T, std::size_t ...I, typename F>
    void tuple_foreach_impl(T &&tuple, std::index_sequence<I...>, F &&func)
    {
        // In C++17 we would use a fold expression here, but in C++14 we have to resort to this.
        using dummy_array = int[];
        dummy_array{(void(func(std::get<I>(tuple))), 0)..., 0};
    }
    
    template <typename T, typename F> void tuple_foreach(T &&tuple, F &&func)
    {
        constexpr int size = std::tuple_size<std::remove_reference_t<T>>::value;
        tuple_foreach_impl(std::forward<T>(tuple), std::make_index_sequence<size>{},
                           std::forward<F>(func));
    }
    
    int main()
    {
        auto x = std::make_tuple("Meow", 1, 2.3);
    
        tuple_foreach(x, [](auto &&value)
        {
            std::cout << value << ' ';
        });
        // Prints:
        // Meow
        // 1
        // 2.3
    }
    

    With tuple_foreach making a proper printer should be simple.

    template <typename T> void print_tuple(const T &tuple)
    {
        std::cout << '{';
        tuple_foreach(tuple, [first = true](auto &value) mutable
        {
            if (!first)
                std::cout << "; ";
            else
                first = 0;
            std::cout << value;
        });
        std::cout << '}';
    }
    
    // ...
    
    print_tuple(std::make_tuple("Meow", 1, 2.3)); // Prints `{Meow; 1; 2.3}`