È possibile “store” di un parametro di modello pack senza espansione?

Sto sperimentando con il C++0x modelli variadic quando mi sono imbattuto in questo problema:

template < typename ...Args >
struct identities
{
    typedef Args type; //compile error: "parameter packs not expanded with '...'
};

//The following code just shows an example of potential use, but has no relation
//with what I am actually trying to achieve.
template < typename T >
struct convert_in_tuple
{
    typedef std::tuple< typename T::type... > type;
};

typedef convert_in_tuple< identities< int, float > >::type int_float_tuple;

GCC 4.5.0 mi da un errore quando cerco di typedef i parametri del modello pack.

In sostanza, vorrei “store” i parametri pack in un typedef, senza aprire la confezione. È possibile? Se non c’è qualche ragione per cui questo non è permesso?

InformationsquelleAutor Luc Touraille | 2011-01-14



4 Replies
  1. 56

    Un altro approccio, che è leggermente più generico rispetto di Ben, è come segue:

    #include <tuple>
    
    template <typename... Args>
    struct variadic_typedef
    {
        //this single type represents a collection of types,
        //as the template arguments it took to define it
    };
    
    template <typename... Args>
    struct convert_in_tuple
    {
        //base case, nothing special,
        //just use the arguments directly
        //however they need to be used
        typedef std::tuple<Args...> type;
    };
    
    template <typename... Args>
    struct convert_in_tuple<variadic_typedef<Args...>>
    {
        //expand the variadic_typedef back into
        //its arguments, via specialization
        //(doesn't rely on functionality to be provided
        //by the variadic_typedef struct itself, generic)
        typedef typename convert_in_tuple<Args...>::type type;
    };
    
    typedef variadic_typedef<int, float> myTypes;
    typedef convert_in_tuple<myTypes>::type int_float_tuple;
    
    int main()
    {}
    • Bello, molto simile a quello che l’OP ha tentato.
    • Molto buona soluzione, io non la penso sull’utilizzo parziale del modello di specializzazione!
    • domanda veloce … questo è stato utile, ma dovrebbe parzialmente versione specializzata effettivamente essere typedef typename convert_in_tuple<Args...>::type type;, o non importa?
    • Quello è corretto. Sono sorpreso che la mia risposta è cavata così a lungo senza un occhio attento se ne accorga. 🙂
    • Baller soluzione! Io amo alla follia che è il C++.
    • Io sarei un po ‘ preoccupato: mentre è molto forte la tentazione di dire “trattare un elenco di tipi, o un’istanza di un tipo particolare che contiene un elenco, come la stessa cosa”, nella mia esperienza, le cose tendono a esplodere disordinatamente quando lo si fa. Come un esempio, immaginate un elenco di lunghezza 1 contenente un variadic_typedef e come interagisce con il codice di cui sopra. Ora immaginate un elenco di tipi di ogni passato in una convert_in_tuple e come interagisce con il codice di cui sopra. Se si avvia l’impostazione di un paio di livelli di indirezione, il trattamento, il contenitore e il contenuto in modo indifferenziato a causa di problemi.
    • Non capisco come questo risolve OP problema. Il convert_in_tuple struct che contiene un alias di un alias di una tupla. Il tipo che rappresenta è una tupla con il parametro Args … pack, e non il parametro Args … pack stesso.

  2. 8

    Penso che il motivo non è permesso è che sarebbe disordinato, e si può lavorare intorno ad esso. È necessario utilizzare inversione delle dipendenze e rendere la struttura memorizzare il parametro pack in una fabbrica modello in grado di applicare tale parametro pack per un altro modello.

    Qualcosa lungo le linee di:

    template < typename ...Args >
    struct identities
    {
        template < template<typename ...> class T >
        struct apply
        {
            typedef T<Args...> type;
        };
    };
    
    template < template<template<typename ...> class> class T >
    struct convert_in_tuple
    {
        typedef typename T<std::tuple>::type type;
    };
    
    typedef convert_in_tuple< identities< int, float >::apply >::type int_float_tuple;
    • Ho provato il tuo codice su GCC 4.5, è solo bisogno di cambiare typename T in class T e modificare il convert_in_tuple parametro per essere un modello modello modello parametro: template < template< template < typename ... > class > class T > struct convert_in_tuple {...} (!).
    • Modificato per essere un modello modello modello di parametro. Sostituzione typename con class si sente un po ‘ dubbia, dal momento che il progetto di: “non C’è nessuna differenza semantica tra class e template, in modello-parametro.”, puoi provare questo nuovo codice?
    • Io non riesco a trovarlo nella norma, ma mi sembra di ricordare che per il modello parametri del modello è necessario utilizzare class e non typename (a causa di un tipo di modello è, inevitabilmente, una classe e non in qualsiasi tipo).
    • Preso a compilare gcc 4.5.2 in una VM, grazie per i puntatori. Ora lottando per ottenere la copia+incolla di VM per lavoro…
    • Infatti, lo standard dice nel paragrafo 14.1.2 che non c’è differenza tra class e typename, ma appena al di sopra (§14.1.1), la sintassi consente solo la class parola chiave nel modello di modello di dichiarazione del parametro. Anche se questo può sembrare incoerente, penso che la logica è, come ho detto prima, che un modello di modello di parametro non può essere di qualsiasi tipo (ad esempio, non può essere int o bool), quindi, forse, il comitato ha deciso che l’uso di typename sarebbe fuorviante. Comunque, torniamo all’argomento :)!
    • La soluzione è bello, ma è triste che abbiamo bisogno di impiegare tali soluzioni alternative…Comunque, è vero che a sostegno di questa in modo pulito potrebbe essere stato un po ‘difficile, ciò avrebbe significato che un typedef potrebbe essere un normale tipo o di un parametro pack, il che è strano…Forse una nuova sintassi potrebbe essere usato, ad esempio un pranzo al typedef’ (typedef ...Args args o qualcosa così).

  3. 3

    Ho trovato Ben Voigt idea molto utile nel mio lavoro. Ho modificato leggermente per renderlo generale, non solo le tuple. Per i lettori qui potrebbe essere una modifica ovvia, ma potrebbe essere la pena di mostrare:

    template <template <class ... Args> class T, class ... Args>
    struct TypeWithList
    {
      typedef T<Args...> type;
    };
    
    template <template <class ... Args> class T, class ... Args>
    struct TypeWithList<T, VariadicTypedef<Args...>>
    {
      typedef typename TypeWithList<T, Args...>::type type;
    };

    Il nome TypeWithList deriva dal fatto che il tipo è ormai un’istanza con un elenco precedente.

  4. 2

    Questa è una variazione di GManNickG pulito parziale specializzazione trucco. Nessuna delega, e si ottiene di più il tipo di sicurezza che richiedono l’uso del vostro variadic_typedef struct.

    #include <tuple>
    
    template<typename... Args>
    struct variadic_typedef {};
    
    template<typename... Args>
    struct convert_in_tuple {
        //Leaving this empty will cause the compiler
        //to complain if you try to access a "type" member.
        //You may also be able to do something like:
        //static_assert(std::is_same<>::value, "blah")
        //if you know something about the types.
    };
    
    template<typename... Args>
    struct convert_in_tuple< variadic_typedef<Args...> > {
        //use Args normally
        typedef std::tuple<Args...> type;
    };
    
    typedef variadic_typedef<int, float> myTypes;
    typedef convert_in_tuple<myTypes>::type int_float_tuple; //compiles
    //typedef convert_in_tuple<int, float>::type int_float_tuple; //doesn't compile
    
    int main() {}
    • Non c’era la ricorsione in @GManNickG risposta, e penso che la possibilità di utilizzo di un raw parametro pack invece di variadic_typedef voleva essere una caratteristica. Quindi, direi che questa risposta è più un degrado di una raffinatezza…
    • Ho capito che la possibilità di non utilizzare un variadic_typedef è stato destinato ad essere una funzione, ma un uomo è un altro uomo di bug. La ragione per cui era in questo thread, in primo luogo, era quello di trovare un modo per fare esattamente quello che la mia risposta qui. Inoltre, c’è un unico ricorsiva “chiamata” in @GManNickG soluzione – quando il variadic_typdef specializzazione parziale di convert_in_tuple “delegati” alla unspecialized versione. Senza di essa, le cose sono un po ‘ più semplice. E infine, ho scelto la parola raffinatezza di non lanciare la mia soluzione migliore, ma più specifici. Ho cambiato il mio testo per riflettere questo.
    • È possibile rimuovere la dipendenza variadic_typedef per convert_in_tuple — fare il template<typename Pack> struct convert_in_tuple {};, allora si specializzano template<template<typename...>class Pack, typename...Args> struct convert_in_tuple<Pack<Args...>> { typedef std::tuple<Args> type; } — ora qualsiasi variardic pack può essere mappato a un tuple.

Lascia un commento