0

I've seen many example codes that use recursion to extract the values from a parameter pack. Is there any way, other than recursion, to extract the values from a parameter pack?

Sapphire_Brick
  • 1,560
  • 12
  • 26
  • The first element would be the degenerate case of recursing once, which is identical to calling one function. Why is that a problem? Is calling a non-recursive function OK? – Useless Apr 26 '20 at 15:02
  • @Useless Because recursion is discouraged; it's compared to a chainsaw. – Sapphire_Brick Apr 27 '20 at 16:39
  • Discouraged by who? What is wrong with chainsaws? – Useless Apr 27 '20 at 22:55
  • @Useless see https://stackoverflow.com/questions/33511917/why-is-it-bad-to-call-functions-recursively – Sapphire_Brick Apr 28 '20 at 00:36
  • `std::get` very likely _is_ recursive, which is why I asked for clarification. It's OK because the depth is fixed, and everything is inlined and optimized away, at compile time. – Useless Apr 28 '20 at 21:51
  • @Useless Oh, I thought so too – Sapphire_Brick Apr 28 '20 at 22:02
  • 1
    Recursion is risky when you don't know in advance how deep it can go (with the possible exception of tail-call recursion with a good optimizer). If it's limited, with a reasonable upper limit, _especially_ one known at compile time - it can be fine, and is pretty frequently used in a compile-time-only way with type packs and old-style typelists (which are themselves recursive). – Useless Apr 28 '20 at 22:07

3 Answers3

1

Depending on what you want to do, you can use C++17 fold expressions:

template <int ... ints>
constexpr int product() {
    return (ints * ...);
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
1

You can forward all pack parameters as a tuple, then call get<0>:

template<class ... Args>
void foo(Args&& ... args) {
    auto&& first = std::get<0>(std::forward_as_tuple(std::forward<Args>(args)...));
}
rafix07
  • 20,001
  • 3
  • 20
  • 33
1

It turns out that it there's a workaround. C++ parameter pack expansions can be used as for each loops:

#include <iostream>

template <int ... ints>
constexpr int product() {
    int ret = 1;
    auto _ = {
        ([&](int i) -> int {
            ret *= i;
            return i;
        })(ints)...
    };
    return ret;
}

int main() {
    std::cout << product<2, 6, 3>() << '\n';
    return 0;
}

The problems are:

  • the above code only works for non-type template parameter packs.
  • there is no break or continue

Edit

Apparently, it's legal to have a goto within a lambda within a parameter pack expansion. (I wasn't aware of this because Clang has a bug that restricts `goto` operands). Nevertheless, it's not a good idea, because it doesn't "clean up" before leaving the lambda.
Sapphire_Brick
  • 1,560
  • 12
  • 26