2012-02-15 17 views
6

Rispondere alla vecchia domanda. Vedi sotto per la risoluzione. Probabilmente è qualcosa di semplice, ma ancora. Ho il seguente C++ 11 frammento di codice:C++ 11 parametri modello template variad.

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

Come posso fare EventStorage ereditare EventContainer templeted con ciascuno dei tipi nella typelist. Potrei farlo con Loki :: library, ma voglio usare C++ 11 con modelli variadic. Grazie.

Risoluzione1: problema di modello di modello di riparazione EventStorage. Questo renderà EventStorage, multiple erediterà tutte le EventContainer con ciascun tipo di Ts.

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

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

}; 

Ora ho compilazione errore di tempo, sul seguente 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] 

Perché il compilatore è confuso? Dopotutto spingo con tipo specifico. GCC 4.6.1 qui.

risoluzione2: Come @Matthieu M. suggerito posso presentare un metodo di inoltro int EventStorage, ma al costo di una chiamata functin in più:

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

Secondo Alexandrescu, il compilatore di ottimizzare questa chiamata in avanti finché i parametri sono riferimenti. Ora la domanda è ufficialmente chiusa :)

risposta

6

C'è qualche motivo per introdurre lo typelist in primo luogo?

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

Questo works e si può typedef tutta Storage<...> bit.

MODIFICA: seguito dei commenti relativi alla possibilità di "combinare" i tipi.

ci sono due soluzioni:

template <typename...> struct CombineStorage; 

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

O semplicemente fornire un adattatore TypeList:

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

Vorrei poter granulare diversi tipi di permutazioni di eventi. Per esempio. 'typedef typelist pumpEvents;' 'typedef typelist displayEvents;' Ma come lo metti in questo modo, vorrei combinare i due 'typelists', se lo storage necessita per memorizzarli entrambi. –

+0

Ho modificato la mia risposta per includere un adattatore 'typelist' e un combinatore di archiviazione. –

+0

Grazie mille. Ci proverò, dopo aver risolto questo problema di ambiguità dai miei altri commenti di risposta. E 'molto strano. 'Push()' gots è sovraccarico? –

1

Al momento, non si è mai nemmeno passa un instantiation TypeList al EventStorage, solo la TypeList modello. Quindi, al momento, è nessun pacchetto di tipi da espandere.

Tuttavia, si dovrebbe essere in grado di scompattare il TypeList con una specializzazione e lavorare con il tipo di confezioni altrimenti:

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

I using dichiarazioni basta tirare tutti i push metodi nello stesso insieme di sovraccarico, che sembra funzionare per me.

L'alternativa sarebbe quella di aggiungere un metodo di template (forse solo alla specializzazione di typelist di toplevel) che inoltra esplicitamente a this->EventContainer<T>::push, ma richiederebbe una corrispondenza di tipo esatta.

+0

Sì, l'ho appena capito da solo. Tuttavia ottengo ambiguità ora. Si supponga che ha aggiunto/sostituito le correzioni ottengo questo: 'errore: richiesta di membro 'push' è ambiguous' ' errore: i candidati sono: EventContainer vuoto :: push (const T &) [con T = Event2] '' EventContainer vuoto :: push (const T &) [con T = Event1] ' principale è: ' int main() { \t EventStorage ev; \t Event1 ev1; \t ev.push (ev1); \t ritorno 0; } ' –

+0

Sì, non ho aggiunto il push bit, ma ci vuole un po 'di manipolazione - editing ora ... – Useless

+0

Ah, ora vedo che c'è un piccolo malinteso. Sono wantihg per ereditare ogni 'EventContainer' ogni template con ogni tipo nella lista di caratteri. Il mio codice è in realtà: ' modello class EventStorage { }; template classe EventStorage >: \t \t EventContainer pubblico ... { }; ' Modifica: Non riesco a formattare sh * t qui. Mi dispiace: ( –

Problemi correlati