2016-04-08 12 views
10

Desidero utilizzare tutti gli elementi di un std::tuple come inizializzatore per una classe. C'è un modo più semplice rispetto a fare std::get<i-th element>(std::tuple) per ogni elemento della tupla?Espandere std :: tuple da utilizzare come inizializzatore per la classe

esempio di lavoro

minimo con std::get:

#include <string> 
#include <tuple> 
#include <cassert> 

struct A 
{ 
    std::string string1; 
    int intVal; 
    std::string string2; 
}; 

int main() 
{ 
    std::tuple< std::string, int, std::string > myTuple("S1", 42, "S2"); 

    A myA{ std::get<0>(myTuple), std::get<1>(myTuple), std::get<2>(myTuple) }; 

    assert(myA.string1 == "S1"); 
    assert(myA.intVal == 42 ); 
    assert(myA.string2 == "S2"); 
} 

Vedi http://coliru.stacked-crooked.com/a/4a5d45dbf1461407 per Live esempio

+6

E.g. vedere [P0209] (http://wg21.link/p0209). –

risposta

5

As Kerrek SB ha commentato c'è già una proposta per questo P0209R0. Di conseguenza, fino a quando è nella norma si potrebbe fare qualcosa in queste righe:

template<typename C, typename T, std::size_t... I> 
decltype(auto) make_from_tuple_impl(T &&t, std::index_sequence<I...>) { 
    return C{std::get<I>(std::forward<T>(t))...}; 
} 

template<typename C, typename... Args, typename Indices = std::make_index_sequence<sizeof...(Args)>> 
decltype(auto) make_from_tuple(std::tuple<Args...> const &t) { 
    return make_from_tuple_impl<C>(t, Indices()); 
} 

e inizializzare la classe come:

A myA{make_from_tuple<A>(myTuple)}; 

Live Demo

Si potrebbe anche a mano artigianali index_sequence e make_index_sequence per questo per funzionare in C++ 11 come proposto da Jarod42here e passare a:

namespace idx { 
    template <std::size_t...> struct index_sequence {}; 

    template <std::size_t N, std::size_t... Is> 
    struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {}; 

    template <std::size_t... Is> 
    struct make_index_sequence<0u, Is...> : index_sequence<Is...> { using type = index_sequence<Is...>; }; 
} 

template<typename C, typename T, std::size_t... I> 
C make_from_tuple_impl(T &&t, idx::index_sequence<I...>) { 
    return C{std::get<I>(std::forward<T>(t))...}; 
} 

template<typename C, typename... Args, typename Indices = idx::make_index_sequence<sizeof...(Args)>> 
C make_from_tuple(std::tuple<Args...> const &t) { 
    return make_from_tuple_impl<C>(t, Indices()); 
} 

Live Demo

+0

La soluzione va bene. Sfortunatamente, questa soluzione richiede C++ 14 che al momento non è disponibile per me. Ho backported backport index_sequence e make_index_sequence così posso ancora usarlo. Bene – meddle0106

+0

@ meddle0106 Proverò a dare anche una versione C++ 11. – 101010

1

Non credo che ci sia qualcosa di standard che potrebbero aiutarvi.

Tuttavia si può fare in questo modo:

fare c-tor in A?

struct A 
{ 
    std::string string1; 
    int intVal; 
    std::string string2; 

    template<class T> 
    A(const T &t) : 
       string1(std::get<0>(t), 
       intVal(std::get<1>(t)), 
       string2(std::get<2>(t)){} 
}; 

In alternativa si può fare in fabbrica come la funzione:

template<class T> 
    A createA(const T &t){ 
     return A { 
       std::get<0>(t), 
       std::get<1>(t), 
       std::get<2>(t) 
     }; 
    } 

codice non è testato e potrebbe avere errori di sintassi.

+0

Poiché si hanno stringhe, si potrebbe fare un po 'più di codice per gestire i riferimenti universali e per 'std :: move' /' std :: forward' le stringhe. – Nick

Problemi correlati