pumpkinjuice
pumpkinjuice

Reputation: 75

c++ iterate over arrays of different types

I have m ints and n floats and I want to iterate over them in one loop. In order to do so, I can think of two possible ways but I don't know if they are actually feasible:

  1. Ideally I want to store the m+n numbers in one array (e.g. in one std::vector), is there a way (a container, or by means of polymorphism) that I could do this?

  2. If I must store the ints and floats in two arrays, is there (or how to write) an iterator that can iterate the two arrays in on loop?

Any idea is welcome!

Upvotes: 1

Views: 1186

Answers (4)

Jarod42
Jarod42

Reputation: 217235

You may factorize your code differently, for example:

struct MyData {

    template <typename FUNC>
    void run(FUNC func) {
         for (auto& i : ints) {
              func(i);
         }
         for (auto& f : floats) {
              func(f);
         }
    }

    std::vector<int> ints;
    std::vector<floats> floats;
};

And then, usage is similar to

MyData myData = /**/;

myData.run([](auto e){ std::cout << e << " "; });

Upvotes: 1

paul-g
paul-g

Reputation: 3877

It seems a template function might be a good solution:

  1. it preserves the semantics of "doing the same for both containers of floats and containers of ints", without creating an artificial container of floats/ints for the sake of saving a few lines of code
  2. from a performance perspective there will be no difference with a hand coded loop iterating over both arrays if you enable compiler optimisations -O3
  3. it will work for other types (e.g. double, int64_t, int32_t etc.)

It would look like this:

template<typename T>
void processData(std::vector<T> data) {
   for (auto& d : data) {
     // do some processing
   }
} 

you would call it with:

processData(std::vector<float>{1.2, 2.5, 3.5, 4.5});
processData(std::vector<int>{1, 2, 3, 4});

see a working example here

Upvotes: 2

Martin Hierholzer
Martin Hierholzer

Reputation: 930

There are several options, with all their different advantages and disadvantages:

  1. Use two std::vector, one for int the other for float, and iterate them in separate loops. If the loop body is non-trivial, put it into a templated function, so you don't have to duplicate the code.

  2. Use an std::vector of boost::any, which can store both floats and ints. When acquiring the value, you have to "cast" it into the right type. Again you might want to put any logic into a templated function to avoid code duplication. Since the boost::any cast to the actual type involves type checking, this solution has not optimal performance. On the other hand it comes close to the behavior of runtime-typed languages like Python.

  3. Especially if you have more then just two types: Use a boost::fusion::map of the type (float and int) to the vector of the type. You can iterate the map with boost::fusion::foreach, which will call a templated function and pass the vectors to it. This way you get essentially the first solution, but this time it scales more easily for many data types.

Since C++ is statically typed, there is no way to have a single container containing both floats and ints without boost::any. Exception: if the number of entries is fixed at compile time, a boost::mpl::vector could help you.

Edit: If you want code examples, give use more information which way you want to go...

Upvotes: 2

Shachar Shemesh
Shachar Shemesh

Reputation: 8573

Either create a struct and use that as your array:

struct my_compund_type {
  int integer;
  float very_narrow_and_possibly_I_meant_double_float;
};

std::vector<my_compund_type> array;

Your other option is to do a for loop that only iterates over the indexes, and access both arrays as necessary.

Upvotes: 0

Related Questions