Wraz z wprowadzeniem std::apply()
, to jest bardzo proste:
template <class Tuple,
class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
std::vector<T> to_vector(Tuple&& tuple)
{
return std::apply([](auto&&... elems){
return std::vector<T>{std::forward<decltype(elems)>(elems)...};
}, std::forward<Tuple>(tuple));
}
std::apply()
jest C++ 17 funkcji, ale jest możliwe do wdrożenia w C + +14 (patrz link do ewentualnej implementacji). Jako ulepszenie możesz dodać SFINAE lub static_assert
, że wszystkie typy w Kodzie są w rzeczywistości T
.
Jako T.C. Zwraca uwagę, to ponosi dodatkową kopię każdego elementu, ponieważ std::initializer_list
jest wspierany przez const
tablicy. To niefortunne. Wygrywamy niektóre z nich, nie musząc sprawdzać granic każdego elementu, ale tracimy trochę na kopiowaniu. Kopiowanie kończy się zbyt drogie, alternatywą byłaby realizacja:
template <class Tuple,
class T = std::decay_t<std::tuple_element_t<0, std::decay_t<Tuple>>>>
std::vector<T> to_vector(Tuple&& tuple)
{
return std::apply([](auto&&... elems) {
using expander = int[];
std::vector<T> result;
result.reserve(sizeof...(elems));
expander{(void(
result.push_back(std::forward<decltype(elems)>(elems))
), 0)...};
return result;
}, std::forward<Tuple>(tuple));
}
Zobacz this answer o wyjaśnienie sztuczki ekspandera. Zauważ, że odrzuciłem wiodącą 0
, ponieważ wiemy, że paczka nie jest pusta. Z C++ 17, to staje się czystsze z rozkładanym wypowiedzi:
return std::apply([](auto&&... elems) {
std::vector<T> result;
result.reserve(sizeof...(elems));
(result.push_back(std::forward<decltype(elems)>(elems)), ...);
return result;
}, std::forward<Tuple>(tuple));
Choć nadal stosunkowo nie tak ładna jak konstruktora initializer_list
. Niefortunny.
Prawdopodobny duplikat [iteracji przez krotkę] (http://stackoverflow.com/questions/1198260/iterate-over-tuple) – filmor
Zupełnie inny. Znacznie lepiej podchodzi się do [sztuczka wskazówka] (http://loungecpp.wikidot.com/tips-and-tricks:indices). – Xeo