I'm attempting to make a variadic template container that stores a tuple of vectors of elements. The point of this container is the elements across all vectors are all related, and I want to maintain that correlation for later, but it isn't necessary for computation. Imagine, if you will, a vector_3 and a ref_id of some type.
The container will only uniformly mutate the vectors together. So the parts I do understand would look like this:
template<typename ...Elems>
class container
{
std::tuple<std::vector<Elems>...> data_;
public:
template<typename I>
const typename std::tuple_element<I, data_type>::type &nth_index() const
{ return std::get<I>(data_); }
};
I'm struggling with an insert method. I was thinking something along the lines of:
void push_back(std::tuple<Elems...> &values)
{
std::tuple<std::back_insert_iterator<std::vector<Elems>>...> inserters;
}
But I have no idea how to initialize this "inserters" tuple. I've been looking at various recursive template examples here on stackoverflow and I can't keep it all in my head long enough to comprehend it.
I was presuming if I had such a tuple, I could use simple assignment:
inserters = values;
I'd also like to write an accessor across all the arrays that returns a tuple of values:
std::tuple<Elems &...> operator[](const size_t index)
{
...
}
But once again, I don't know how to initialize this tuple.
I can't be the only one who ever wanted to do this and I can't find a good resource to learn it. In the meantime, I'm trying to digest the original variadic template proposal for 0x. Insight would be appreciated. I'm limited by the MSVC 2012 implementation.
A C++11 solution with SFINAE and type traits:
template<typename ...Elems>
class container {
std::tuple<std::vector<Elems>...> data_;
template<std::size_t N>
typename std::enable_if<(N <std::tuple_size<decltype(data_)>::value), int>::type
push_back_impl(std::tuple<Elems...> const &values) {
std::get<N>(data_).push_back(std::get<N>(values));
return push_back_impl<N + 1>(values);
}
template<std::size_t N>
typename std::enable_if<(N == std::tuple_size<decltype(data_)>::value), int>::type
push_back_impl(std::tuple<Elems...> const &values) {
return 0;
}
public:
void push_back(std::tuple<Elems...> const &values) {
push_back_impl<0>(values);
}
};
as for the subscript operator you'll need some extra machinery found in this SO answer:
template <size_t ...I>
struct index_sequence {};
template <size_t N, size_t ...I>
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {};
template <size_t ...I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
template<typename ...Elems>
class container {
std::tuple<std::vector<Elems>...> data_;
template<size_t ...I>
std::tuple<Elems&...> access_impl(std::size_t const idx, index_sequence<I...>) {
return std::tie(std::get<I>(data_)[idx]...);
}
public:
std::tuple<Elems&...> operator[](std::size_t const idx) {
return access_impl(idx, make_index_sequence<sizeof...(Elems)>());
}
};