考虑以下(幼稚的)C ++代码片段,将对象从自定义列表类型转移到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);
}
}
现在,假设一个人有一个std::vector
的自定义列表,并且想弄平结构,或者一个std::vector
的矢量。天真的,我现在继续编写这种类型的函数。
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);
}
}
等等,依此类推。但是我看到这不是很优雅,因为我需要每个深度级别的此功能的版本。我可以想象有一种使用一些模板魔术来解决此问题的更优雅的方法,但我的知识不足,无法提出一种真正更好的解决方案。
使用模板抽象出矢量深度级别的“推荐”方法是什么,这样只需编写flatten_transfer
的单个实例?
答案 0 :(得分:6)
假设我正确理解了这个问题,以下函数模板在C ++ 17及更高版本中可以很好地实现此目的。
当且仅当target.push_back(elem)
与A
相同时,此函数才会实例化B
。
否则,将进入下一个深度:
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);
}
}
}
这是一个用法示例:
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 << " ";
}