C ++ 11 template template template options

Saving the old question. See below for permission. This is probably something simple, but still. I have the following C ++ 11 code snippet:

#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 an EventStorage inherit an EventContainer bookmark each type in a typelist . I could do this using the Loki :: library, but I want to use C ++ 11 with variable templates. Thanks.

Resolution 1: Fix EventStorage template EventStorage . This will make EventStorage somewhat inherit all EventContainer templates with each Ts type.

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

Now I have a compile time error, 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 is the compiler confusing? In the end, I click on a specific type. GCC 4.6.1 here.

resolution2: Since @Matthieu M. suggested that I introduce an int EventStorage forwarding method, but with one extra call to functin:

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

According to Alexandrescu, the compiler optimizes this direct call while the parameters are references. Now the question is officially closed :)

+6
source share
2 answers

Is there any reason to introduce 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 one works , and you can typedef whole bit of Storage<...> .

EDIT . Follow the comments regarding the ability 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 specify an adapter like:

 template <typename... Args> class Storage<typelist<Args...>>: public Storage<Args...> {}; 
+6
source

At the moment, you are not even transferring a copy with copyright to EventStorage, but only a list template. So, there is currently no package type extension.

However, you should be able to unpack the list of types with specialization and work with type packages 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; }; 

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

An alternative would be to add a template method (perhaps only to a specialized specialized specialization), which explicitly goes into this->EventContainer<T>::push , but this requires an exact type match.

+1
source

Source: https://habr.com/ru/post/908519/


All Articles