2016-04-08 13 views
10

Chcę użyć wszystkich elementów std::tuple jako inicjalizatora dla klasy. Czy istnieje prostszy sposób niż wykonanie std::get<i-th element>(std::tuple) dla każdego elementu krotki?Rozwiń std :: tuple, aby użyć jako inicjalizatora dla klasy

Minimalna przykład pracy z 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"); 
} 

Zobacz http://coliru.stacked-crooked.com/a/4a5d45dbf1461407 do Live przykład

+6

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

Odpowiedz

5

Jako Kerrek SB skomentował już wniosek dla tego P0209R0. W związku z tym, dopóki nie jest w normie można zrobić coś wzdłuż tych linii:

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()); 
} 

i zainicjować swoją klasę jako:

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

Live Demo

Można również ręcznie rzemiosła index_sequence i make_index_sequence dla to do pracy w C++ 11, jak zaproponował Jarod42here, i zmień na:

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

Rozwiązanie jest w porządku. Niestety, to rozwiązanie wymaga C++ 14, który jest obecnie niedostępny dla mnie. Zablokowałem backport index_sequence i make_index_sequence, więc nadal mogę z niego korzystać. W porządku – meddle0106

+0

@ meddle0106 Spróbuję też podać wersję C++ 11. – 101010

1

Nie sądzę, nie ma nic, że norma może pomóc.

Jednak można to zrobić w następujący sposób:

Czy c-tor w 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)){} 
}; 

Alternatywnie można zrobić fabrykę funkcji jak:

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

Code jest niesprawdzone i mogą mieć błędy składniowe.

+0

Ponieważ masz ciągi znaków, możesz zrobić więcej kodu, aby obsłużyć uniwersalne odniesienia i 'std :: move' /' std :: forward' ciągi. – Nick

Powiązane problemy