2012-02-15 17 views
6

Guardando la vieja pregunta. Vea a continuación para la resolución. Probablemente sea algo simple, pero aún así. Tengo el siguiente C++ 11 fragmento de código:C++ 11 parámetros de plantilla de plantilla variadic

#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; 
} 

¿Cómo puedo hacer EventStorage hereda EventContainer templeted con cada uno de los tipos en el typelist. Podría hacerlo con Loki :: library, pero quiero usar C++ 11 con plantillas variadas. Gracias.

Resolución 1: problema de plantilla de plantilla de fijación EventStorage. Esto hará que EventStorage herede múltiples EventContainer plantilla con cada tipo de Ts.

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

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

}; 

Ahora tengo error de compilación tiempo, en el siguiente 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] 

Por qué se confunde el compilador? Después de todo, presiono con un tipo específico. GCC 4.6.1 aquí.

resolución2: Como @Matthieu M. sugirió que puedo presentar un método de reenvío int EventStorage, pero a un costo de una llamada adicional functin:

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

Según Alexandrescu, el compilador optimizar este desvío de llamadas siempre que los parámetros sean referencias. Ahora la pregunta se cerró oficialmente :)

Respuesta

6

¿Hay alguna razón para introducir el typelist en primer lugar?

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; 
} 

Este works y se puede typedef todo el Storage<...> bits.

EDIT: A raíz de los comentarios sobre la posibilidad de "combinar" tipos.

hay dos soluciones:

template <typename...> struct CombineStorage; 

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

O simplemente proporcionar un adaptador typelist:

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

Ojalá pudiera granular diferentes tipos de permutaciones 'Event'. P.ej. 'typedef typelist pumpEvents;' 'typedef typelist displayEvents;' Pero como usted lo dice, me gustaría combinar las dos 'typelists', si el almacenamiento lo necesita para almacenarlos a ambos. –

+0

Edité mi respuesta para incluir un adaptador 'typelist' y un combinador de almacenamiento. –

+0

Muchas gracias. Voy a intentar eso, después de resolver este problema de ambigüedad de los demás, responder el comentario. Es muy extraño. ¿No está sobrecargado 'push()' gots? –

1

Por el momento, estás ni siquiera pasando un instanciación typelist a la EventStorage, sólo el typelist plantilla. Por lo tanto, actualmente, es sin tipo de paquete para expandir.

Sin embargo, usted debe ser capaz de descomprimir el typelist con una especialización y trabajar con el tipo de paquetes de otro modo:

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; 
}; 

Los using declaraciones simplemente tirar de todos los métodos push en el mismo conjunto de sobrecarga, que parece funcionar para mi.

La alternativa sería agregar un método de plantilla (tal vez solo a la especialización de lista de tipos de nivel) que explícitamente reenvía a this->EventContainer<T>::push, pero requeriría una coincidencia de tipo exacta.

+0

Sí, lo descubrí por mi cuenta. Sin embargo, ahora tengo ambigüedad. Suponga que los agregados reemplazados sus correcciones/me sale esto: 'error: solicitud de miembro de 'empuje' es ambiguous' ' error: los candidatos son: void EventContainer :: push (const T &) [con T = Evento2] ' ' void EventContainer :: push (const T &) [con T = Evento1] ' principal es: ' int main() { \t EventStorage ev; \t Event1 ev1; \t ev.push (ev1); \t return 0; } ' –

+0

Sí, no agregué el bit de inserción, pero se necesita un poco de manipulación: edición ahora ... – Useless

+0

Ah, ahora veo que hay un pequeño malentendido. Quiero heredar cada 'EventContainer' cada plantilla con cada tipo en' typelist'. Mi código es en realidad: ' plantilla clase EventStorage { }; plantilla clase EventStorage >: \t \t EventContainer pública ... { }; ' Editar: No puedo formatear sh * t aquí. Lo siento :( –

Cuestiones relacionadas