Questo è effettivamente possibile, con le caratteristiche di C++ 11.
Sì, l'inizializzatore_list desidera che tutti gli elementi siano dello stesso tipo. Il trucco è che possiamo creare una classe wrapper che può essere static_cast
per tutti i tipi che vogliamo. Questo è facile da raggiungere:
template <typename... tlist>
class MultiTypeWrapper {
};
template <typename H>
class MultiTypeWrapper<H> {
public:
MultiTypeWrapper() {}
MultiTypeWrapper(const H &value) : value_(value) {}
operator H() const {
return value_;
}
private:
H value_;
};
template <typename H, typename... T>
class MultiTypeWrapper<H, T...>
: public MultiTypeWrapper<T...> {
public:
MultiTypeWrapper() {}
MultiTypeWrapper(const H &value) : value_(value) {}
// If the current constructor does not match the type, pass to its ancestor.
template <typename C>
MultiTypeWrapper(const C &value) : MultiTypeWrapper<T...>(value) {}
operator H() const {
return value_;
}
private:
H value_;
};
Con i costruttori conversione implicita, possiamo passare qualcosa come {1,2.5, 'c', 4} a un initializer_list (o un vettore, che converte implicitamente l'initializer_list) di tipo MultiTypeWrapper. Ciò significa che non possiamo scrivere una funzione come sotto ad accettare tale intializer_list come argomento:
template <typename... T>
std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
....
}
Usiamo un altro trucco per lanciare ogni valore nel vettore al suo tipo originale (notare che forniamo conversione implicita in la definizione di MultiTypeWrapper
) e assegnarla allo slot corrispondente in una tupla. E 'come una ricorsione sugli argomenti di template:
template <int ind, typename... T>
class helper {
public:
static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
std::get<ind>(t) = static_cast<typename std::tuple_element<ind,std::tuple<T...> >::type>(v[ind]);
helper<(ind-1),T...>::set_tuple(t,v);
}
};
template <typename... T>
class helper<0, T...> {
public:
static void set_tuple(std::tuple<T...> &t, const std::vector<MultiTypeWrapper<T...> >& v) {
std::get<0>(t) = static_cast<typename std::tuple_element<0,std::tuple<T...> >::type>(v[0]);
}
};
template <typename... T>
std::tuple<T...> create_tuple(std::vector<unit_test::MultiTypeWrapper<T...> > init) {
std::tuple<T...> res;
helper<sizeof...(T)-1, T...>::set_tuple(res, init);
return res;
}
Nota che dobbiamo creare la classe di supporto per set_tuple
dal C++ non supporta la funzione di specializzazione.Ora, se vogliamo testare il codice:
auto t = create_tuple<int,double,std::string>({1,2.5,std::string("ABC")});
printf("%d %.2lf %s\n", std::get<0>(t), std::get<1>(t), std::get<2>(t).c_str());
Il risultato sarebbe:
1 2.50 ABC
Questo è testato sul mio desktop con clangore 3.2
Speranza aiuta il mio ingresso :)
Scusate! Ho fatto un refuso, riadattato, ma ancora non funzionerà! – Need4Steed
@ Need4Steed Aggiornato la mia risposta. –
Ho provato make_tuple, funziona bene, ma mi sembra incoerente se va bene con le coppie ma non con le tuple. – Need4Steed