Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Virtually sequentially concatenate two C++ std::vectors

My question consists of two parts:

First part. Am I correct that the following task couldn’t be solved in C++ even with recent innovations in templates?

The goal is to virtually (which means no real concatenation should occur) sequentially concatenate two C++ std::vectors of objects of different types for the time of function call.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

My understanding that this is not doable since it is impossible at compile time to generate the code that will handle objects of different types (in the function) without usage of dynamic polymorphism.

Details for both parts follow below. Now is the second part. What is the simplest way to solve this task in case vectors contain the elements of the same type?

I have objects of some classes in different vectors and want some function to process them as whole. I don’t want to use virtual functions, dynamic memory allocation neither put all objects of different types (pointers to them) in the same container, since in most of code they treated differently and I don’t won’t to pay extra price neither to make complicated interfaces for my classes.

The code below is taken from the answer from Evg to satisfy request from AlanBirtles in comment below for minimal reproducible example.

#include <vector>
#include <iostream>

struct A {
  void foo() { std::cout << "Hey, I'm A!\n"; }
};

struct B {
  void foo() { std::cout << "Hey, I'm B!\n"; }
};

void bar(???) {
}

int main()  {
    std::vector<A> va(2);
    std::vector<B> vb(3);

    bar(???);
    return 0;
}

Of course, I can process all these vectors one by one, but I have many of them and this would lead to code duplication and risks of forgetting to update such code when a new type is added.

I am sure that for the elements of the same type in vectors this could be done by a new container class that wraps all these containers and provides iterators for them, but is there a simpler way to make this on the fly?

>Solution :

You could do some metaprogramming using variadic parameter packs and fold expressions. For example:

template<class... Ts>
void bar(Ts&... vecs) {
    const auto call_foo_for_each = [](auto& vec) {
        for (auto& v : vec)
            v.foo();
    };
    (call_foo_for_each(vecs), ...);
}

void caller()  {
    bar(va, vb /*, ... */);
}

Demo

If you want to pass them as a single argument, you could pack them into a tuple (of references):

template<class... Ts>
void bar(std::tuple<Ts...> tuple) {
    const auto call_foo_for_each = [](auto& vec ) {
        for (auto& v : vec)
            v.foo();
    };
    std::apply([&](auto&... vecs) {
        (call_foo_for_each(vecs), ...);
    }, tuple);
}

void caller()  {
    bar(std::make_tuple(std::ref(va), std::ref(vb) /*, ... */));
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading