2

I am trying to print all the values of pair inside of a tuple,

header file

template <typename... Args>
void printPairs(std::tuple<Args...> t)
{
    for (int i = 0; i <= 4; i++)  //the value of 'i' is not usable in a constant expression
    {
        auto pair = std::get<i>(t);
        cout << pair.first << " " << pair.second << endl;
    }
}

Main.cpp

std::tuple<std::pair<int, int>, std::pair<int, int>, std::pair<int, int>, std::pair<int, int>> t1 = {std::make_pair(1, 2), std::make_pair(3, 4), std::make_pair(5, 6), std::make_pair(7, 8)};
printPairs(t1);

If you would not iterate and put a constant value instead of "i", works fine

auto pair = std::get<1>(t);
 cout << pair.first << " " << pair.second << endl;
n9p4
  • 304
  • 8
  • 34
  • The `for` loop is something which is executed at run-time but you try to resolve compile-time indexes with `std::get<>`. You would need something like `for constexpr` (which doesn't exist AFAIK). You could try to use recursion or fold expressions... – Scheff's Cat Jan 29 '22 at 16:13
  • FYI: [SO: compile time loops](https://stackoverflow.com/questions/6872919/compile-time-loops) (It's a bit aged.) [SO: c++ generic compile-time for loop](https://stackoverflow.com/q/55648387/7478597), or just [google "c++ compile time iteration"](https://www.google.com/search?q=c%2B%2B+compile+time+iteration) by yourself. ;-) – Scheff's Cat Jan 29 '22 at 16:16

3 Answers3

4

You can use std::apply:

template<typename Tuple>
void printPairs(const Tuple& t) {
  std::apply([](const auto&... pair) {
    ((std::cout << pair.first << " " << pair.second << std::endl), ...);
  }, t);
}
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
2

Something along these lines, perhaps:

template <typename... Args, size_t... Is>
void printPairsHelper(const std::tuple<Args...>& t, std::index_sequence<Is...>) {
    ((std::cout << std::get<Is>(t).first << " "
                << std::get<Is>(t).second << std::endl), ...);
}

template <typename... Args>
void printPairs(const std::tuple<Args...>& t)
{
    printPairsHelper(t, std::make_index_sequence<sizeof...(Args)>{});
}

Demo

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
1

There is no way to print elements of a tuple in a loop because, as it was already explained in one of the comments, loops (for, while etc.) are evaluated at run-time and to iterate over tuple you'd need something that works at compile-time.

One solution that I see would be to first write a little utility function(s):

#include <tuple>
#include <utility>

template<std::size_t... Ints, typename... Args, typename Proc>
void forEachImpl(std::tuple<Args...> const& tuple, Proc&& proc, std::index_sequence<Ints...>) {
    (..., proc(std::get<Ints>(tuple)));
}

template<typename... Args, typename Proc>
void forEach(std::tuple<Args...> const& tuple, Proc&& proc) {
    forEachImpl(tuple, proc, std::index_sequence_for<Args...>());
}

The one which we're going to use is forEach (forEachImpl is just an implementation helper function used by forEach). What it does is, it calls proc with each element of tuple as an argument.

Then we can go back to your function - printPairs - and the main function:

#include <iostream>

template<typename... Args>
void printPairs(std::tuple<Args...> const& tuple) {
    forEach(tuple, [] (auto const& pair) {
        std::cout << pair.first << ' ' << pair.second << '\n';
    });
}

int main() {
    std::tuple t(std::pair(1, 3), std::pair('x', 'y'), std::pair(-5.3f, 3.7L));
    printPairs(t);
}
navyblue
  • 776
  • 4
  • 8