1

I have a class containing a tuple of functions, with their return types determined by the template of the class:

template <typename... Ts>
class A{
    static inline auto funcs = std::make_tuple(std::function<Ts()>()...)
};

I would like to be able to iterate over these functions. I tried getting the indexes of each type from the template using the method from this answer: https://stackoverflow.com/a/26169248/

std::get<Index<Ts,Ts...>::value>(funcs)()...;

But this code doesn't compile. It complains about the "..." at the end, possibly because the template parameter pack was already expanded when I typed "T...", but I don't see why it won't let me expand the other "Ts". Is there a way to do this?

  • 1
    What C++-version are you using? If 17: try add a `,` beforr the `...`. – n314159 Dec 10 '19 at 22:06
  • I'm using C++17. Adding a comma didn't seem to do anything―I tried both in GCC and MSVC. MSVC's error is "unexpected token '...', expected expression" and GCC's error is "expected ';' before '...' token" – meatandmahjong Dec 10 '19 at 22:16

1 Answers1

3

You have to remove the {} in your funcs assignment otherwise this will create an initializer_list and not a tuple

static inline auto funcs = std::make_tuple(std::function<Ts()>()...);

Then you can call each tuple function with help of std::apply and a generic variadic lambda:

auto call = [](auto&&...funcs) {
    (funcs(),...);
};

int main()
{
    A<int, float, char> l;
    std::get<0>(l.funcs) = []() { cout << "Calling int()" << endl; return 1; };
    std::get<1>(l.funcs) = []() { cout << "Calling float()" << endl; return 1.f; };
    std::get<2>(l.funcs) = []() { cout << "Calling char()" << endl; return '1'; };

    std::apply(call, l.funcs);
    return 0;
}

See the live example: https://onlinegdb.com/HJfQ95TpS

Gerard097
  • 815
  • 4
  • 12
  • Thanks, this works! I'm a bit curious why it has to be a generic lambda though, and why something like @n314159 suggested doesn't work? – meatandmahjong Dec 10 '19 at 22:33
  • 1
    What he suggested does work, but you have to wrap the expression with parenthesis as I did in call function https://stackoverflow.com/a/33868734/7908019. If I had used a variadic template instead of the generic lambda we would have to specify the template arguments when calling std::apply i.e. std::apply(call&>...); take a look https://onlinegdb.com/BylOWoaaS. – Gerard097 Dec 10 '19 at 22:51
  • Very interesting! Say we wanted to store the return values in a tuple though, how would we go about getting them out of the std::apply? This seems simpler if we're using variadic templates. Something like this, though it doesn't compile when you ask for multiple types, and I don't see why: https://onlinegdb.com/H1p3cop6S – meatandmahjong Dec 10 '19 at 23:31
  • 1
    Just remove the , and the parenthesis, also fix the index while assigning the functions of your tuple https://onlinegdb.com/Hy4wOxkRr. – Gerard097 Dec 11 '19 at 23:16