2016-08-11 22 views
5

W języku C++, w jaki sposób mogę zaimplementować funkcję z int argumentem szablonu wskazującym długość krotki i generującą std :: tuple o tej długości?Wywołaj std :: tuple tego samego typu w czasie kompilacji, biorąc pod uwagę jego długość przez argument szablonu

E.g.

func<2>() returns std::tuple<int, int>(); 
func<5>() returns std::tuple<int, int, int, int, int>(). 
+0

Co próbowaliście do tej pory? – user2079303

+2

obowiązkowe: czy rozważałeś użycie tylko 'std :: array'? Możesz użyć 'tablica' podobnie jak krotka (z' std :: tuple_size', 'std :: get', etc) i bardzo by to uprościć. –

+0

@ user2079303, moją intuicją jest utrzymywanie listy typów, odliczanie od N do 0 i dodawanie int do listy, gdy licznik jest zmniejszany. Gdy N wynosi 0, zwraca tę krotkę z listą typów. Ale nie wiem, jak to wykonać. – yuefengz

Odpowiedz

5

to na rekursywne rozwiązanie z szablonem aliasu i implementowalne w C++ 11:

template <size_t I,typename T> 
struct tuple_n{ 
    template< typename...Args> using type = typename tuple_n<I-1, T>::template type<T, Args...>; 
}; 

template <typename T> 
struct tuple_n<0, T> { 
    template<typename...Args> using type = std::tuple<Args...>; 
}; 
template <size_t I,typename T> using tuple_of = typename tuple_n<I,T>::template type<>; 

na przykład, jeśli chcemy "tuple of 3 doubles" możemy napisać:

tuple_of<3, double> t; 
5

Używanie index_sequence i rodzajem pomocnika alias można wygenerować typ chcesz:

// Just something to take a size_t and give the type `int` 
template <std::size_t> 
using Integer = int; 

// will get a sequence of Is = 0, 1, ..., N 
template <std::size_t... Is> 
auto func_impl(std::index_sequence<Is...>) { 
    // Integer<Is>... becomes one `int` for each element in Is... 
    return std::tuple<Integer<Is>...>{}; 
} 

template <std::size_t N> 
auto func() { 
    return func_impl(std::make_index_sequence<N>{}); 
} 

Warto wołając, że w ogólnym przypadku będzie prawdopodobnie być lepiej z std::array (w twoim przypadku nie możesz go użyć), ale std::array może zachowywać się jak krotka, podobnie jak std::pair.

Aktualizacja: ponieważ jasno dałeś do zrozumienia, że ​​pracujesz z wersją C++ 11, a nie 14+, musisz uzyskać implementację index_sequence i pokrewną gdzieś (here to libC++). Oto wersja C++ 11 func i func_impl z wyraźnych typów obie strony:

template <std::size_t... Is> 
auto func_impl(std::index_sequence<Is...>) -> std::tuple<Integer<Is>...> { 
    return std::tuple<Integer<Is>...>{}; 
} 

template <std::size_t N> 
auto func() -> decltype(func_impl(std::make_index_sequence<N>{})) { 
    return func_impl(std::make_index_sequence<N>{}); 
} 
+2

Zauważ, że to jest C++ 14. – Yakk

+0

Czy można zaimplementować za pomocą C++ 11? – yuefengz

+1

@Fake tak, jeśli możesz uzyskać implementację 'index_sequence', a następnie dodać jawne typy powrotu do funkcji. Czy twoje pytanie powinno być oznaczone jako 'C++ 11'? –

3

Równina stary rekurencji jest twoim przyjacielem:

template<std::size_t N> 
auto array_tuple() { 
    return std::tuple_cat(std::tuple<int>{}, array_tuple<N-1>()); 
} 

template<> 
auto array_tuple<0>() { 
    return std::tuple<>{}; 
} 
+1

Może być przydatne określenie standardu C++ 14, który jest potrzebny dla funkcji zwracania 'auto'. –

+0

To jest dobra uwaga. Czy możemy całkowicie polegać na C++ 11? – yuefengz

2

Jeśli jesteś w porządku z C++ 14 rozwiązanie, Ryan's answer jest drogą do zrobienia.

z C++ 11, można wykonać następujące czynności (wciąż na podstawie index_sequence, ale to jest możliwe do wdrożenia w C++ 11):

template <size_t N, class T, class = std::make_index_sequence<N>> 
struct n_tuple; 

template <size_t N, class T, size_t... Is> 
struct n_tuple<N, T, std::index_sequence<Is...>> { 
    template <size_t > 
    using ignore = T; 

    using type = std::tuple<ignore<Is>...>; 
}; 

template <size_t N, class T> 
using n_tuple_t = typename n_tuple<N, T>::type; 

Mając to:

template <size_t N> 
n_tuple_t<N, int> func() { 
    return n_tuple_t<N, int>{}; 
} 
+0

Wygląda na to, że index_sequence jest nadal funkcją C++ 14. Czy to możliwe, aby nie polegać również na tym? – yuefengz

+1

Prawdopodobnie mogę po prostu skopiować implementację index_sequence. – yuefengz

+0

@Fake Tak, jak stwierdziłem w odpowiedzi, można go zaimplementować w C++ 11 – Barry