6

Keeping the old question. See below for resolution. It is probably something simple, but still. I have the following C++11 code fragment:

#include <vector>

template <typename... Ts>
struct typelist
{
};

template <typename T>
struct EventContainer
{
    typedef T Type;
    /// TODO. Ring buffer
    std::vector<T> container;

    void push(const T& t)
    {
        EventContainer<T>::container.push_back(t);
    }

    virtual ~EventContainer()
    {
    }
};


template <template <typename...> class TL>
class EventStorage:
        public EventContainer<Ts>...
{

};

class Event1
{
};

class Event2
{
};

typedef typelist<Event1,Event2> Events12;

int main()
{
    EventStorage<Events12> ev;

    return 0;
}

How can I make EventStorage inherit EventContainer templeted with each of the types in the typelist. I could do it with Loki:: library, but I want to use C++11 with variadic templates. Thank you.

Resolution1: Fixing EventStorage template template issue. This will make EventStorage, multiple inherit all EventContainer templated with each type of Ts.

template <typename...>
class EventStorage
{
};

template <typename... Ts>
class EventStorage < typelist<Ts...> >:
        public EventContainer<Ts>...
{

};

Now I have compile time error, on the following main():

int main()
{
    EventStorage<Events12> ev;
    Event1 ev1;
    ev.push(ev1);

    return 0;
}

In function ‘int main()’:
error: request for member ‘push’ is ambiguous
error: candidates are: void EventContainer<T>::push(const T&) [with T = Event2]
error: void EventContainer<T>::push(const T&) [with T = Event1]

Why the compiler is confused? After all I push with specific type. GCC 4.6.1 here.

Resolution2: As @Matthieu M. suggested I can present a forwarding method int EventStorage, but at a cost of one extra functin call:

template <typename T>
void push(const T& t)
{
    EventContainer<T>::push(t);
}

According to Alexandrescu, the compiler will optimize this forward call as long as parameters are references. Now the question is officially closed :)

2 Answers 2

6

Is there any reason for introducing the typelist in the first place ?

template <typename T> struct Template { void push(T) {} };

template <typename... Args>
class Storage: public Template<Args>...
{
public:
  // forwarding...
  template <typename T>
  void push(T t) {
    Template<T>& me = *this;
    me.push(t);
  }
};

int main() {
  Storage< int, char > storage;
}

This works and you can typedef the whole Storage<...> bit.

EDIT: Following on comments regarding the possibility to "combine" types.

There are two solutions:

template <typename...> struct CombineStorage;

template <typename... A, typename... B>
struct CombineStorage<Storage<A...>, Storage<B...>> {
  typedef Storage<A..., B...> type;
};

Or simply provide a typelist adapter:

template <typename... Args>
class Storage<typelist<Args...>>: public Storage<Args...> {};
Sign up to request clarification or add additional context in comments.

7 Comments

I wish I could granulate different kinds of Event permutations. E.g. typedef typelist<Event1,Event2> pumpEvents; typedef typelist<Event3,Event4,Event5> displayEvents; But as you put it that way, I would want to combine the two typelists, if the storage need to store them both.
I edited my answer to include a typelist adapter and a storage combinator.
Thank you very much. I will try that, after I solve this ambiguity issue from my others answer comment. It is very strange. Isn't push() gots overloaded?
Overload resolution with inheritance doesn't seem completely intuitive: the solution in my answer works, but does feel ugly.
Top answer here is the most concise answer I've found: essentially the compiler finds the first scope with one or more of overloads of the right name, and stops looking. Overload resolution, implicit conversions etc. are applied only to this set of candidates. stackoverflow.com/questions/72010/c-overload-resolution
|
1

At the moment, you're never even passing a typelist instantiation to the EventStorage, just the typelist template. So currently, there is no type pack to expand.

However, you should be able to unpack the typelist with a specialization and work with type packs otherwise:

template <typename...> class EventStorage;

template <typename Head, typename... Tail> class EventStorage<Head, Tail...>
  : public EventContainer<Head>, EventStorage<Tail...>
{
  using EventContainer<Head>::push;
  using EventStorage<Tail...>::push;
};

// allows you to pass typelists for convenience
template <typename... TL> class EventStorage<typelist<TL...>>
  : public EventStorage<TL...>
{
  using EventStorage<TL...>::push;
};

The using declarations just pull all the push methods into the same overload set, which seems to work for me.

The alternative would be to add a template method (maybe just to the toplevel typelist specialization) which explicitly forwards to this->EventContainer<T>::push, but it would require an exact type match.

4 Comments

Yes, I just figured it out myself. However I get ambiguity now. Assume that added/replaced your fixes I get this: error: request for member ‘push’ is ambiguous error: candidates are: void EventContainer<T>::push(const T&) [with T = Event2] void EventContainer<T>::push(const T&) [with T = Event1] Main is: ` int main() { EventStorage<Events12> ev; Event1 ev1; ev.push(ev1); return 0; } `
Yeah, I didn't add the push bit, but it takes a little fiddling - editing now ...
Ah, now I see that there is a little misunderstanding. I am wantihg to inherit every EventContainer each templated with each type in the typelist. My code is actually: ` template <typename... Ts> class EventStorage { }; template <typename... Ts> class EventStorage < typelist<Ts...> >: public EventContainer<Ts>... { }; ` Edit: I just can't format sh*t here. I am sorry:(
Don't worry, the comments aren't ideal for lots of code :-) Just edit it into the end of your question, and I'll take a look.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.