Consider the following (naive) piece of C++ code to transfer objects from a custom list type into a std::vector
template<class A> void transfer(std::vector<A>& target, const custom_list_type& source){
  for(const A& elem:source){
    target.push_back(elem);
  }
}
Now, imagine one had a std::vector of such custom lists and would want to flatten the structure, or a std::vector of such vectors. Naively, I would now go ahead and write functions of this type.
template<class A> void flatten_transfer(std::vector<A>& target, const std::vector<custom_list_type>& source){
  for(const auto& elem:source){
    flat_transfer(target,elem);
  }
}
template<class A> void flatten_transfer(std::vector<A>& target, const std::vector<std::vector<custom_list_type> >& source){
  for(const auto& elem:source){
    flat_transfer(target,elem);
  }
}
And so on and so forth. But I see that this is not very elegant, because I need a version of this function of every depth level. I would imagine there is a more elegant way to solve this using some template magic, but I'm not really knowledgeable enough to come up with a solution that is genuinely nicer.
What would be the "recommended" way to abstract away the vector-depth-level using templates, such that only a single instance of flatten_transfer would need to be written?
Assuming that I correctly understand the problem, the following function template well works for this purpose in C++17 and over.
This function instantiates target.push_back(elem) if and only if A is same with B.
Otherwise, this goes to the next depth:
Live DEMO
template<
    class A,
    class B,
    template <class...> class Container,
    class... extras>
void flat_transfer(std::vector<A>& target, const Container<B, extras...>& source)
{
    for(const auto& elem : source)
    {
        if constexpr(std::is_same<A, B>::value){
            target.push_back(elem);
        }
        else{
            flat_transfer(target, elem);
        }
    }
}
This is an usage example:
std::vector<int> v{1,2,3};
std::set<std::vector<std::deque<int>>, std::greater<>> vv{{{4,5}, {6,7}, {8,9}}, {{10,11,12}, {13,14}, {15}}};
flat_transfer(v, vv);
// prints "1 2 3 10 11 12 13 14 15 4 5 6 7 8 9" 
for(const auto& i : v){
    std::cout << i << " ";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With