2015-09-07 24 views
7

Abbastanza sicuro di sapere già la risposta, ma vale la pena provare.Posso dichiarare una specializzazione template da una lista di caratteri?

Quindi, dire che ho un TypeList:

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

che contiene alcuni oggetti:

struct foo{}; 
struct bar{}; 
struct quux{}; 

using objects = typelist<foo, bar, quux>; 

Ora ho una classe template (baz) che può prendere uno di questi oggetti. Ma, a causa della dimensione del codice base e dei tempi di compilazione, voglio avere l'implementazione del mio metodo basato su modelli in un file cpp.

Quindi in fondo baz.cpp ho:

template <> class baz<foo>; 
template <> class baz<bar>; 
template <> class baz<quux>; 

Il problema è che ho un sacco di classi come baz, e l'elenco degli oggetti che essi lavorano con è anche in continua evoluzione. Quindi ... c'è comunque che posso mantenere la mia singola lista di oggetti e usarla nel file cpp di ogni oggetto-baz-like per specializzarmi? Quindi, tutto ciò che devo fare è aggiornare la mia lista di caratteri quando ho un nuovo oggetto e tutti i file oggetto verranno ricostruiti.

+0

Non è necessario * specializzare *, solo esplicitamente * istanziare * loro. – Jarod42

+0

Questo potrebbe sicuramente essere fatto usando una macro. Dato che questo sarà isolato dal resto della tua base di codice, perché non farlo? –

risposta

9

L'inoltro di riga template <> class baz<foo>;-indica una specializzazione e non un'istanza di modello, che, presumo, è ciò che si desidera.

Non penso che ci sia un modo diretto per farlo, dovrete fare qualche metaprogrammazione. È possibile utilizzare Boost.Preprocessor per generare tutto il codice necessario:

#define TYPES (foo)(bar)(quux) 

using objects = typelist< BOOST_PP_SEQ_ENUM(TYPES) >; 

// Generate extern template declarations in the header 
#define EXTERN_TEMPLATE_BAZ(r, data, arg)\ 
    extern template class baz<arg>; 

BOOST_PP_SEQ_FOR_EACH(EXTERN_TEMPLATE_BAZ, _, TYPES) 

// Generate template instantiations in the .cpp 
#define TEMPLATE_BAZ(r, data, arg)\ 
    template class baz<arg>; 

BOOST_PP_SEQ_FOR_EACH(TEMPLATE_BAZ, _, TYPES) 

Ci può essere un modo per fare questo senza preprocessore ma facendo questo potrebbe imporre requisiti supplementari sul tipo baz. Il punto è usare il tipo in un contesto in cui deve essere istanziato, inclusi tutti i suoi metodi.

+0

Non tutti usano boost e non ci sono note su boost nella domanda. –

+2

Quindi? È comunque una soluzione valida. –

+0

Questa soluzione funziona, ma forse non è ciò che voleva il richiedente. Boost non fa parte del C++ standard. –

3

Sono abbastanza sicuro che questo è impossibile senza utilizzare il preprocessore. Potresti essere in grado di ricostruire il template pack template da un argomento, ma devi effettivamente passare un'istanza dell'argomento, che sembra non ottimale. In secondo luogo, le istanze di template esplicite non sono consentite nell'ambito del blocco (cioè in una funzione template), quindi non c'è modo di scrivere un template che istanzia esplicitamente un altro template.

Come indica Nir, perché non usi semplicemente uno X Macro?

#define MY_FOREACH_TYPES(func, ...) \ 
    func(type1, ##_VA_ARGS__) \ 
    func(type2, ##_VA_ARGS__) \ 

#define MY_INSTANTIATE(Type, Class) \ 
    template <> class Class<Type>; 

MY_FOREACH_TYPES(MY_INSTANTIATE, bar) 

Ora aggiornare MY_FOREACH_TYPES quando l'elenco dei tipi cambia.

+0

Grazie mille per aver parlato di X-Macro. Il link wiki è il migliore! Sai cosa impedisce alla gente di non usare X Macro? (eccetto che è più difficile da tracciare/eseguire il debug) – javaLover

2

Una versione di lavorare con un preprocessore normale

//Header file 

#define BAZ_OBJS \ 
    BAZ_BEGIN foo \ 
    BAZ_AND  bar \ 
    BAZ_AND  quux \ 
    BAZ_END 

#define BAZ_BEGIN 
#define BAZ_AND , 
#define BAZ_END 
using objects = typelist<BAZ_OBJS>; 
#undef BAZ_BEGIN 
#undef BAZ_AND 
#undef BAZ_END 

#define BAZ_BEGIN BAZ_EXTERN template class baz< 
#define BAZ_END >; 
#define BAZ_AND BAZ_END BAZ_BEGIN 

#ifdef MY_IMPLEMENTATION_CPP //cpp should define it before including the header file 
#define BAZ_EXTERN 
#else 
#define BAZ_EXTERN extern 
#endif 

BAZ_OBJS 
3

Per prima cosa: la sintassi corretta per esplicito modello di classe di istanza è

template class baz<foo>; 
template class baz<bar>; 
template class baz<quux>; 
non

template <> class baz<foo> che è la classe esplicito modello di specializzazione (forward-dichiarazione).

Una possibilità potrebbe essere quella di creare un'istanza di una classe che assomiglia a questo

template <template <typename> class T, typename... Args> 
class for_each_class : T<Args>... 
{ 
}; 

// Instantiate 
template class for_each_class<baz, foo, bar, quux>; 

che costringerebbero esemplificazione implicita di baz<foo>, baz<bar>, baz<quux>. Bene, ma si desidera creare questo da typelist. Lo typelist è un modello già specializzato e non esiste alcun modo in C++ per iterare tramite i parametri del modello in typelist dal "mondo esterno di typelist".

Un'altra possibilità potrebbe essere l'utilizzo della macro, ma anche in macro non è possibile utilizzare l'originale typelist. Vorrei concludere il tuo problema non ha soluzione con dato typelist.

Come soluzione, se possibile, lascerei l'istanziazione del modello sul compilatore. I modelli non utilizzati non sono istanziati in questo caso. La compilazione lenta è dovuta al modo in cui lo meta-programs are specified.

+0

Ciò non istituirebbe 'baz ', 'baz ', o 'baz '. – Barry

+0

Poiché i membri che sono modelli non vengono istanziati. – Barry

+0

@Barry Per favore leggi di nuovo il mio post. Non sto dicendo che ciò creerà un'istanza di 'baz ' ecc. Ma sto spiegando perché questo non può essere fatto senza macro. –

1

Questo sarebbe il trucco. Alla fine con una secializzazione dell'elenco di caratteri con solo uno (o nessuno) tipi.

template <typename Head, typename ...Tail> 
struct typelist{ 
    typedef baz<Head> head_t; 
    typedef typelist<Tail...> tail_t; 
}; 
+0

No, non crea un'istituzione di 'baz'. –

+0

Cosa succede se 'baz ' era un attributo di 'typelist '? Al momento non riesco a testarlo; il compilatore più recente che ho ottenuto è gcc4.3. – prgasp77

+0

Quale attributo? Non sono a conoscenza di attributi che eseguono l'istanziazione del modello. –