2

TL;DR below

I am trying to write some C++ code using a package for multicore processing. The package has a nice sender class that I use to send messages between the threads. It looks something like this:

// structs provided by the package
struct GlobalVarsContainer {
    // some global vars
};

template<typename ...Ts>
struct sender {
    GlobalVarsContainer* my_container;
    sender (GlobalVarsContainer& c) : my_container(&c);
    void send(Ts... args) {
        // send the messages of types Ts
    };
};

The constructor of this class is actually a bit more involved, so I would like to have the constructor called only once. I tought of using a container-type for all the senders I need, so something like this:

typedef std::tuple<
    sender<uint32_t,uint32_t>,
    sender<uint32_t,double>,
    sender<uint32_t,double>
> sender_container_1_t;
typedef std::tuple<
    sender<uint32_t,double>,
    sender<uint32_t,double>,
    sender<uint32_t,double>
> sender_container_2_t;

Now I can construct a sender_container_1_t and pass it by reference to all my functions, hurray! But this is ugly, and you have to instantiate the container like so:

GlobalVarsContainer gvc1, gvc2;
sender_container_1_t c1(gvc1, gvc1, gvc1);
sender_container_2_t c2(gvc2, gvc2, gvc2);

And I would like to have something of the form

GlobalVarsContainer gvc1, gvc2;
// Should have a tuple of senders of type sender<uint32_t,uint32_t>, sender<uint32_t,double> and sender<uint32_t,double>, all constructed with a reference to gvc as an argument.
sender_container<uint32_t,double,double> c1(gvc1);
// Should have a tuple of senders of type sender<uint32_t,double>, sender<uint32_t, double> and sender<uint32_t, double>, all constructed with a reference to gvc as an argument.
sender_container<double,double,double> c2(gvc2);

So I thought of using a variadic container struct, like so:

// My sender container
template<typename... Ts>
struct SenderContainer {
    std::tuple<sender<uint32_t, Ts>...> my_senders;
    // What to do for the constructor ?
};

But I do not know what to do such that I can do SenderContainer<uint32_t,double,double> my_container(gvc1) such that the gvc1 is forwarded to the constructor of all the senders. Does anyone have a tip?

TL;DR: If I have a variadic struct template

template<typename ...Ts>
struct Bar {
    Bar(Foo f){};
}

Can I make a container of the form

template<typename ...Ts>
struct BarContainer{
    std::tuple<Bar<int,Ts>...> bars
}

such that I can call BarContainer<int, double, long> newBarContainer(f) and the Foo f is forwarded to all constructors of the BarContainer::bars.

0RR
  • 1,538
  • 10
  • 21
student91
  • 213
  • 1
  • 10

1 Answers1

3

You can create dummy structure to allow your pack expansion:

template <typename> struct tag{};

template<typename ...Ts>
struct Bar {
    Bar(Foo f){};
};

template<typename ...Ts>
struct BarContainer{
    BarContainer(Foo f) : bars{(tag<Ts>{}, f)...} {}

    std::tuple<Bar<int,Ts>...> bars;
}

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302