2015-08-15 12 views
6

Desidero utilizzare i tipi di un pacchetto di parametri del modello come parametri per un modello diverso, ma tagliare l'ultimo parametro.Rimuovere l'ultimo tipo di un gruppo di parametri del modello

Ad esempio:

template <class... Ts> struct some_template; 

template <class... Ts> struct foo 
{ 
    using bar = some_template<magically_get_all_but_last(Ts)...>; 
}; 

// I might be missing a few "typename"s, but you get the idea. 
static_assert(std::is_same<foo<int, bool, std::string>::bar, some_template<int,bool> >::value); 

noti che questo è l'opposto di getting only the last parameter.

+1

la chiave potrebbe essere usando qualcosa come make_index_sequence stijn

+0

@stijn Grazie! Non posso ancora usare C++ 14, ma mi hai dato una spinta nella giusta direzione. –

+1

@TobiasBrandt: se giochi con i pacchetti di parametri con C++ 11 consiglio vivamente di creare la tua versione di 'index_sequence' e famiglia! –

risposta

4

Ecco un approccio semplice che utilizza std::tuple_element<I, Tuple> insieme a std::index_sequence<sizeof...(Ts) - 1 per ottenere tutto tranne l'ultimo tipo in un elenco di argomenti variadici. Dal momento che il pacchetto di parametri per gli indici è necessario, esiste un'ulteriore indiretta che viene inserita in una base ma potrebbe essere ovunque.

template <class T, class... Ts> struct foobase; 
template <std::size_t... I, class... Ts> 
struct foobase<std::index_sequence<I...>, Ts...> { 
    using bar = some_template<typename std::tuple_element<I, std::tuple<Ts...>>::type...>; 
}; 

template <class... Ts> struct foo 
    : foobase<std::make_index_sequence<sizeof...(Ts) - 1>, Ts...> 
{ 
}; 
+0

Grazie, questa è una buona soluzione quando puoi usare C++ 14. –

+1

'std :: index_sequence' e la famiglia può essere implementata con C++ 11. Non erano solo parte della libreria standard. Quindi ti consiglio di creare la tua versione. I punti [proposta n3658] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html), ad esempio, in [questo approccio] (http: // stackoverflow. COM/a/14059084/1120,273 mila). –

+1

@tobias nota che per gli elenchi estremamente lunghi, la sequenza di indicizzazione legata non è ideale: per 10-20ish, va bene. – Yakk

0

Questo sembra funzionare:

#include <tuple> 
#include <utility> 
#include <cstdint> 

using std::size_t; 
using std::tuple; 

namespace 
{ 
    template <class Tuple, template <class...> class Template> struct apply_tuple_params_impl {}; 
    template <template <class...> class Template, class... Params> 
    struct apply_tuple_params_impl<tuple<Params...>, Template> 
    { 
     typedef Template<Params...> type; 
    }; 

    template <class Param, class Tuple> struct extend_tuple; 
    template <class Param, class... Params> struct extend_tuple<Param, tuple<Params...>> 
    { 
     typedef tuple<Param, Params...> type; 
    }; 

    template <class Param, class... Params> struct all_but_last_type_tuple_impl 
    { 
     typedef typename extend_tuple<Param, typename all_but_last_type_tuple_impl<Params...>::type>::type type; 
    }; 

    template <class Param> struct all_but_last_type_tuple_impl<Param> 
    { 
     typedef tuple<> type; 
    }; 
} 

// pass the template parameters of a tuple to another template 
template <class Tuple, template <class...> class Template> 
using apply_tuple_params = typename apply_tuple_params_impl<Tuple, Template>::type; 

// a tuple type with all the parameters except the last 
template <class... Params> 
using all_but_last_type_tuple = typename all_but_last_type_tuple_impl<Params...>::type; 

e usarlo in questo modo:

template <class... Ts> struct some_template; 

template <class... Ts> struct foo 
{ 
    typedef apply_tuple_params<all_but_last_type_tuple<Ts...>, some_template> bar; 
}; 

static_assert(std::is_same<foo<int, bool, std::string>::bar, some_template<int,bool> >::value, ""); 
3

Qui è la mia soluzione che utilizza C++ 11:

template <typename ...P> 
struct dummy {}; 

template <template <typename ...> class Obj, typename T, typename ...P> 
struct internal; 

template <template <typename ...> class Obj, typename ...P1, typename T, typename ...P2> 
struct internal<Obj, dummy<P1...>, T, P2...> 
{ 
    using type = typename internal<Obj, dummy<P1..., T>, P2...>::type; 
}; 

template <template <typename ...> class Obj, typename ...P1, typename T, typename L> 
struct internal<Obj, dummy<P1...>, T, L> 
{ 
    using type = Obj<P1..., T>; 
}; 

template <template <typename ...> class T, typename ...P> 
struct subst_all_but_last 
{ 
    using type = typename internal<T, dummy<>, P...>::type; 
}; 

Utilizzare in questo modo:

using bar = typename subst_all_but_last<some_template, Ts...>::type; 

invece di

using bar = some_template<magically_get_all_but_last(Ts)...>; 
+0

Grazie, meglio del mio. –

+0

@TobiasBrandt Grazie! :) – HolyBlackCat

Problemi correlati