2013-03-14 4 views
8

C'è un modo per strip a std::tuple<T...> per tornare a T...?Come rimuovo una tupla <> in un elenco di tipi di modelli variadici?

Esempio

Supponiamo vct<T...> è un preesistentemodello di classe variadic,

using U = std::tuple<int,char,std::string>; 
using X = vct<int,char,std::string>; 
using Y = vct< strip<U> >;   // should be same as X 

Note

che so di std::tuple_element, ma ho bisogno di tutto il elementi, in una forma che è utilizzabile come T...

Per avere un riferimento, ho trovato questo question, che è simile, ma le mie esigenze sono un po 'più semplici (quindi spero che ci sia una soluzione più semplice): tutto quello che serve è l'elenco dei tipi che sono in tuple - Non mi interessa i valori effettivi di un'istanza tuple.

risposta

9

No, questo non è possibile. I pacchetti di argomenti sono il risultato della deduzione di tipo e non possono essere prodotti in altri contesti.

Si potrebbe fare qualcosa di simile a quello che stai chiedendo in questo modo:

template<template<typename...> class T, typename> 
struct instantiate_with_arg_pack { }; 

template<template<typename...> class T, typename... Ts> 
struct instantiate_with_arg_pack<T, std::tuple<Ts...>> 
{ 
    using type = T<Ts...>; 
}; 

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

int main() 
{ 
    using U = std::tuple<int,char,std::string>; 
    using X = vct<int,char,std::string>; 
    using Y = instantiate_with_arg_pack<vct, U>::type; 
} 

In realtà, non c'è bisogno di tenere il pacco argomento in una tupla: qualsiasi modello di classe variadic è OK:

template<template<typename...> class T, typename> 
struct instantiate_with_arg_pack { }; 

template< 
    template<typename...> class T, 
    template<typename...> class U, // <=== 
    typename... Ts 
    > 
struct instantiate_with_arg_pack<T, U<Ts...>> 
//         ^^^^^^^^ 
{ 
    using type = T<Ts...>; 
}; 

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

int main() 
{ 
    using U = std::tuple<int,char,std::string>; 
    using X = vct<int,char,std::string>; 
    using Y = instantiate_with_arg_pack<vct, X>::type; 
    //          ^

    // Won't fire 
    static_assert(
     std::is_same<Y, vct<int,char,std::string>>::value, 
     "Error!"); 
} 

E qui è un live example.

+3

+1 Bel tocco con il parametro template template. –

3

È possibile non direttamente "ritorno" di un parametro pacchetto, in modo da che cosa avete bisogno è qualcosa di simile:

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

template< typename T > 
struct make_vct; 

template< typename... Ts > 
struct make_vct< std::tuple<Ts...> > 
{ 
    typedef vct<Ts...> type; 
}; 

e utilizzare

using Y = make_vct<U>::type; 
8
template<typename> 
struct strip; 

template<typename ...T> 
struct strip<std::tuple<T...>> 
{ 
    using type = vct<T...>; 
}; 

quindi utilizzare questo come:

using Y = strip<U>::type; 

Ora Y è uguale come X.

+3

+1 per brevità. – Yakk

2

L'obiettivo qui è di essere in grado di copiare un pacchetto di parametri da un'istanza di un modello, in un altro modello. Non l'ho limitato a tuple, perché ... perché limitarlo a tuple?

template<template<typename...>class Target, typename Src> 
struct copy_pack_types; 

template<template<typename...>class Target, template<typename...>class Src, typename... Ts> 
struct copy_pack_types< Target, Src<Ts...> > { 
    typedef Target<Ts...> type; 
}; 

template<template<typename... Ts>class Target, typename Src> 
using CopyPackTypes = typename copy_pack_types<Target, Src>::type; 

#include <string> 
#include <tuple> 
template<typename... Ts> struct vct; 
template<typename... Ts> struct vct2; 
using U = std::tuple<int,char,std::string>; 
using X = vct<int,char,std::string>; 
using Y = CopyPackTypes< vct, U >;   // should be same as X 
using Z = CopyPackTypes< vct2, U >;   // should be different from X 

#include <iostream> 
#include <type_traits> 
int main() { 
    std::cout << std::is_same< X, Y >::value << "\n"; 
    std::cout << std::is_same< Z, Y >::value << "\n"; 
    std::cout << std::is_same< Z, vct2<int,char,std::string> >::value << "\n"; 
} 

l'uscita è "1 0 1" come previsto.

Lo CopyPackTypes utilizza un modello di destinazione e un tipo di origine creato da un pacchetto di parametri come unico argomento. Quindi copia il pacchetto di parametri nel modello di destinazione.

Una tecnica standard è da trasportare pacchi parametri intorno è di creare un altrimenti no tipo utilizzare come:

template<typename...> 
struct types {}; 

che esiste solo come segnaposto per un elenco dei tipi. È quindi possibile passare alcuni di questi a un altro modello, e ogni pacchetto non "si calpestano" a vicenda. Quando è necessario applicarlo a un modello di destinazione, si utilizza qualcosa come sopra "CopyPackTypes" per applicarlo.

Tecniche simili sono utilizzati per pacchi di indici:

template<size_t...> 
struct seq {}; 

tipi altrimenti inutili che sono "liste nere" per trasportare ciuffi di parametri intorno.