将多个向量(函数结果)用模板合并成一个

5

我希望有一个模板函数,接受一个vector <T> v和一个函数op,将T映射到vector <U>,并希望连接应用于每个向量元素的f的结果,以返回vector <U>= [ op(v[0])中的元素,op(v[1])中的元素... ]。

我发现一种有效的解决方案是在函数中添加一个例子,以允许进行模板推断:

template <typename Container>
Container& concat(Container& c1, Container const& c2) {
  c1.insert(end(c1), begin(c2), end(c2));
  return c1;
}

template <typename Container, typename UnaryOperation, typename U>
inline auto to_vec_from_vectors(Container& c, UnaryOperation&& op, U& ex)
    -> std::vector<U> {
  std::vector<U> v;
  for (auto& e : c) {
    std::vector<U> opv = op(e);
    concat(v, opv);
  }
  return v;  
}

但是我希望只使用这两个参数就能达到相同的效果。 我的尝试[用decltype(*std::begin(op(*std::begin(c))))替换U]:

template <typename Container, typename UnaryOperation, typename U>
inline auto to_vec_from_vectors(Container& c, UnaryOperation&& op, U& ex)
    -> std::vector<decltype(*std::begin(op(*std::begin(c))))> {
  std::vector<decltype(*std::begin(op(*std::begin(c))))> v;
  for (auto& e : c) {
    std::vector<decltype(*std::begin(op(*std::begin(c))))> opv = op(e);
    concat(v, opv);
  }
  return v;  
}

很遗憾,这段代码没有编译成功。如果操作对象是复杂方法,我也担心会浪费时间。
这就是输出结果:
error: conversion fromstd::vector<U>’ to non-scalar typestd::vector<const U&, std::allocator<const U&> >’ requested

error: forming pointer to reference typeconst U&

看起来与“const”有关。

如何纠正这个变体?是否有更好的替代方案?


1
问题在于你的 decltype(...) 给出的是 const U&,而不是 U。因此编译器报错。 - Max Langhof
在第二种情况下,为什么要保留 Uex - Holt
与您的问题无关,但根据 U 的情况,您可能希望在连接时移动而不仅仅是复制,例如 v.insert(end(v), std::make_move_iterator(begin(opv)), std::make_move_iterator(end(opv)));。或者在调用 concat 时重载 concatstd::move(opv) - Holt
1个回答

5
迭代器的解引用会产生一个引用(如果容器是const,则产生一个const引用)。这就是为什么根据你的编译错误,decltype(*std::begin(op(*std::begin(c)))) 产生 const U& 而不是 U。您可以通过使用std::remove_reference(或者,如果您还想删除constvolatile,请使用std::remove_cvref)来再次删除引用,或者只需要求向量实际存储的内容: decltype(*std::begin(op(*std::begin(c)))) -> typename decltype(op(*std::begin(c)))::value_type。我已经删除了不需要的U& ex参数。
template <typename Container, typename UnaryOperation>
inline auto to_vec_from_vectors(Container& c, UnaryOperation&& op)
    -> std::vector<typename decltype(op(*std::begin(c)))::value_type> {
  std::vector<typename decltype(op(*std::begin(c)))::value_type> v;
  for (auto& e : c) {
    std::vector<typename decltype(op(*std::begin(c)))::value_type> opv = op(e);
    concat(v, opv);
  }
  return v;  
}

演示

你也可以通过命名来避免三次重复使用 decltype

template <typename Container, typename UnaryOperation>
using applied_op_t = typename decltype(std::declval<UnaryOperation>()(*std::begin(std::declval<Container>())))::value_type;

1
你可以使用 auto 来避免重复输入 opv,而且显然 decltype(to_vec_from_vectors(c, op)) 可以用于 v(不确定其合法性)。 - Holt
@Holt 或者你可以省略尾部的返回类型... 但是这段代码总体上存在很多混淆。我决定不去完善它,因为它的规范性严重不足 ;) - Max Langhof
在C++11中,您不能跳过尾部返回类型。 - Holt
@Holt 哎呀,完全忘记了语言标签。我的错! - Max Langhof
哇...这真的值得点赞!太难跟上了! - UserUsing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接