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