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

car*_*ten 5 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,假设有人拥有一个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);
  }
}
Run Code Online (Sandbox Code Playgroud)

等等等等。但是我看到这不是很优雅,因为我需要每个深度级别的此功能的版本。我可以想象有一种使用一些模板魔术来解决此问题的更优雅的方法,但是我并不了解足够多的知识,无法提出真正更好的解决方案。

使用模板抽象出矢量深度级别的“推荐”方法是什么,从而只flatten_transfer需要编写一个实例?

Hir*_*oki 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个用法示例:

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 << " ";
}
Run Code Online (Sandbox Code Playgroud)