c ++递归模板解析:优雅地将向量的向量展平

时间:2019-04-16 10:03:16

标签: c++ templates vector

考虑以下(幼稚的)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的单个实例?

1 个答案:

答案 0 :(得分:6)

假设我正确理解了这个问题,以下函数模板在C ++ 17及更高版本中可以很好地实现此目的。 当且仅当target.push_back(elem)A相同时,此函数才会实例化B。 否则,将进入下一个深度:

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);
        }
    }
}

这是一个用法示例:

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 << " ";
}