0

Given,

template<typename T>
void foo(T t)
{
    std::tie(/*xxx*/)=t;
    auto &[/*yyy*/]=t;
}
int main()
{
    foo(forward_as_tuple(1,2,3));
    foo(forward_as_tuple(1,2,3,4,5));
}

I want foo() to unpack the tuple that's passed to itself. Can decomposition declarations with auto or std::tie(), handle the unknown tuple sizes like xxx - yyy up there?
If yes, how?

I'm trying to think of another ways, maybe all elements could be pushed back to a vector of that type, once they're got.

std::vector<T> bar;
size_t baz=std::tuple_size<T>::value; //useless because it can't be used as:
for(int i=0; i<baz; i++)
    bar.push_back(std::get<i>(t)); //since i isn't constant

Using vectors was just a bad idea that failed.
How else can it be done?

What I'm trying to, shortly is; I want to get tuple elements in a for loop. That's why I think I need them to be extracted somehow.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982

2 Answers2

3

What I'm trying to, shortly is; I want to get tuple elements in a for loop.

You don't need to unpack a tuple to iterate over it. Here's how I'd do it:

template <typename Integer, Integer ...I, typename F>
constexpr void constexpr_for_each(std::integer_sequence<Integer, I...>, F &&func)
{
    (func(std::integral_constant<Integer, I>{}) , ...);
}

template <auto N, typename F>
constexpr void constexpr_for(F &&func)
{
    if constexpr (N > 0)
    {
        constexpr_for_each(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
    }
}

template <typename T>
void foo(T t)
{
    constexpr_for<std::tuple_size_v<T>>([&](auto index)
    {
        constexpr auto i = index.value;

        std::cout << std::get<i>(t) << '\n';
    });
}
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • This works perfectly but I can't understand the logic behind it. I haven't learned about _constant expressions_ yet. I'll check it about it, thanks. –  May 11 '20 at 15:11
3

How to unpack tuple with unknown size?

auto &[/*yyy*/]=t;

You can't.

maybe all elements could be pushed back to a vector of that type

Use std::apply:

std::vector<int> baz;
std::apply([&baz](auto... args) {
    (baz.push_back(args), ...);
}, t);
Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Can you show me a small example on how it's done? I tried to use your solution but can't compile. It says `expansion pattern 'int' contains no argument packs` –  May 11 '20 at 15:09
  • 2
    `int...` doesn't work here. It has to be `auto...`, or `std::same_as auto...` if you want to show off. :P – HolyBlackCat May 11 '20 at 15:12
  • @HolyBlackCat Good catch. I didn't verify correctness. – eerorika May 11 '20 at 15:16
  • I couldn't compile it also with `auto...`. Can you please verify it and show how it will compile well? –  May 11 '20 at 15:21
  • @Xemdocia When program does not compile, first step is to read the error message. – eerorika May 11 '20 at 15:23
  • @eerorika Now, it compiles well after your edit. Thank you very much –  May 11 '20 at 15:27