Variadic template with class names

66 views Asked by At

I've this template

template <typename T> 
class Publisher
{
public:
    Publisher(){}
    ~Publisher(){}
}

and I've this variadic template

template <typename First, typename... Rest>
class PublisherContainer
{
    PublisherContainer();
    ~PublisherContainer();
}

In the PublisherContainer constructor I want to create a Publisherfor every template argument:

template <typename First, typename... Rest>
PublisherContainer<First, Rest...>::PublisherContainer()
{
    Publisher<First> publisher;
    // create other publisher here.
}

So I can do

PublisherContainer<ClassA, ClassB, ClassC> myPublisher;

How can I invoke Publisher for every template argument?

2

There are 2 answers

3
Kerrek SB On

Class templates cannot have "pack members". Parameter packs must either be forwarded or unpacked; they cannot be used like types.

The easiest answer is to not reinvent the wheel and use the purpuse-built product type, std::tuple:

template <typename ...Args>
struct PublisherContainer
{
    std::tuple<Publisher<Args>...> publisher;
};

(Note that "container" is probably a bad name, since in the idiom of standard C++, containers are things that model iterable ranges of elements. A tuple is a product ("one of each"), not a range. Maybe "PublisherHolder" is more appropriate, or drop the wrapper layer entirely and just use tuples directly.)

4
RamblingMad On

Kerrek SB is semi-correct in his answer. It is correct that you cannot have packed members in the way you are currently trying to do this, but you can do it with inheritance.

First we will define a base class:

template<typename T>
class PublisherBase{
    public:
        int some_member;
        void some_method(){}
};

then we need a class to contain our base:

template<typename T>
class Publisher{
    public:
        PublisherBase<T> self;
};

then we create our holder or 'container'

template<typename First, typename ... Rest>
class PublisherContainer: public Publisher<First>, Publisher<Rest>...{};

which we can use like so:

int main(int argc, char *argv[]){
    PublisherContainer<int, float, double, short> container;
    container.Publisher<float>::self.some_method();
    container.Publisher<short>::self.some_member = 5;
}

The syntax is kinda weird, but it achieves what you asked. The only issue with this approach is that you are restricted to only one publisher per type; but that also may be desired.