Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::apply with variadic packs

I am trying to create a generic class that takes a pack of types, stores them in a tuple, and can apply a function over them.

What I tried so far is the following:

#include <tuple>
struct Base{
    virtual void base_function() = 0;
};

template<typename ...T>
struct A : public Base{
    std::tuple<T...> as;
    A(T... pack):as(pack...){};
    void base_function(){
        std::apply([](auto t){t.base_function();}, as);
    }
};

struct B : public Base{
    void base_function(){};
};


struct C : public Base{
    void base_function(){};
};

struct D : A<B, C>{
    D():A(B(),C()){};
};

I expected apply to be called on base_function from class B and C when calling base_function on D. But the compiler generates the following error:

error: no matching function for call to
'__invoke(A<T>::base_function() [with T = {B, C}]::<lambda(auto:1)>, std::__tuple_element_t<0, std::tuple<B, C> >&, std::__tuple_element_t<1, std::tuple<B, C> >&)'

like image 676
sqrtroot Avatar asked Feb 11 '19 13:02

sqrtroot


1 Answers

First parameter of std::apply should be a functor with same arity that number of elements of the tuple, so variadic in your case:

template <typename ...Ts>
struct A : public Base{
    std::tuple<Ts...> as;
    A(Ts... pack) : as(pack...){}

    void base_function(){
        std::apply([](auto&... ts){(ts.base_function(), ...);}, as);
    }
};
like image 84
Jarod42 Avatar answered Oct 06 '22 00:10

Jarod42