1

I have a collection of vectors of different types like this:

std::vector<int> a_values;
std::vector<float> b_values;
std::vector<std::string> c_values;

Everytime i get a new value for a, b and c I want to push those to their respective vectors a_values, b_values and c_values.

I want to do this in the most generic way possible, ideally in a way I can iterate over the vectors. So I want a function addValue(...) which automatically calls the respective push_back() on each vector. If I add a new vector d_values I only want to have to specify it in one place.

The first answer to this post https://softwareengineering.stackexchange.com/questions/311415/designing-an-in-memory-table-in-c seems relevant, but I want to easily get the vector out for a given name, without having to manually cast to a particular type. ie. I want to call getValues("d") which will give me the underlying std::vector.

Does anyone have a basic example of a collection class that does this?

user3055163
  • 471
  • 4
  • 10

1 Answers1

1

This idea can be achieved with the heterogenous container tuple, which will allow for storage of vectors containing elements of different types.

In particular, we can define a simple data structure as follows

template <typename ...Ts>
using vector_tuple = std::tuple<std::vector<Ts>...>;

In the initial case, of the provided example, the three vectors a_values, b_values, c_values, simply corresponds to the type vector_tuple<int, float, std::string>. Adding an additional vector simply requires adding an additional type to our collection.

Indexing into our new collection is simple too, given the collection

vector_tuple<int, float, std::string> my_vec_tup;

we have the following methods for extracting a_values, b_values and c_values

auto const &a_values = std::get<0>(my_vec_tup);

auto const &b_values = std::get<1>(my_vec_tup);

auto const &c_values = std::get<2>(my_vec_tup);

Note that the tuple container is indexed at compile-time, which is excellent if you know the intended size at compile-time, but will be unsuitable otherwise.

In the description of the problem that has been provided, the number of vectors does appear to be decided at compile-time and the naming convention appears to be arbitrary and constant (i.e., the index of the vectors won't need to be changed at runtime). Hence, a tuple of vectors seems to be a suitable solution, if you associate each name with an integer index.

As for the second part of the question (i.e., iterating over each vector), if you're using C++17, the great news is that you can simply use the std::apply function to do so: https://en.cppreference.com/w/cpp/utility/apply All that is required is to pass a function which takes a vector (you may wish to define appropriate overloading to handle each container separately), and your tuple to std::apply.

However, for earlier versions of C++, you'll need to implement your own for_each function. This problem has fortunately already been solved: How can you iterate over the elements of an std::tuple?