【问题标题】:Perfect forwarding container element完善的转发容器元素
【发布时间】:2015-04-21 18:01:11
【问题描述】:

类似于this question,但不是完美的对象转发成员,我想知道如何完善STL容器的转发元素,即类似于

struct X {};
void f(X&);
void f(X&&);

template <typename Vector>
void g(Vector&& v, size_t i) {
  if (is_lvalue_reference<Vector>::value) {
    f(v[i]);
  } else {
    f(move(v[i]));
  }
}

【问题讨论】:

  • 你能举个例子说明你想做什么吗?
  • @Barry,我已遵循规则 sscce.org 将其修剪为最小大小写。实际用例很复杂。我想从vector&lt;U1&gt;vector&lt;U2&gt;、......创建vector&lt;T&gt;,其中每个元素T是从U1U2、......每个数组vector&lt;Ui&gt;构造的可以是 & 或 &&,我希望 Ui 被完美转发。
  • @Barry 目标是从v[i] 转移,如果v 绑定到右值。

标签: c++ c++11 perfect-forwarding


【解决方案1】:
namespace detail {
    template<class T, class U>
    using forwarded_type = std::conditional_t<std::is_lvalue_reference<T>::value,
                                              std::remove_reference_t<U>&, 
                                              std::remove_reference_t<U>&&>;
}
template<class T, class U>
detail::forwarded_type<T,U> forward_like(U&& u) {
    return std::forward<detail::forwarded_type<T,U>>(std::forward<U>(u));
}

template <typename Vector>
void g(Vector&& v, size_t i) {
  f(forward_like<Vector>(v[i]));
}

Demo。在实现中使用std::forward 会自动防止您将右值作为左值进行危险的转发。

针对您的实际用例

我想从vector&lt;U1&gt;vector&lt;U2&gt;、...创建vector&lt;T&gt;,其中 每个元素 T 都是从 U1, U2, ... 构造的。每个数组 vector&lt;Ui&gt; 可以是 &amp;&amp;&amp;,我希望 Ui 是 完美转发。

这就变成了

template<class T, class...Vectors>
std::vector<T> make_vector(Vectors&&...vectors){
    auto n = std::min({vectors.size()...});
    std::vector<T> ret; 
    ret.reserve(n);
    for(decltype(n) i = 0; i < n; ++i)
        ret.emplace_back(forward_like<Vectors>(vectors[i])...);
    return ret;
}

【讨论】:

  • 那么,如果我们有一个左值引用的右值元组引用,forward_like&lt;Tuple&gt;( get_tuple_member(t) ) 应该返回一个右值还是左值?我想我们无法从访问器函数中区分“成员”和“引用成员”。也许我们应该做std::forward&lt;Vector&gt;(v)[i]vector::operator[] 应该有一个右值重载?嗯。理论上,std::forward&lt;Foo&gt;(foo).field 是我们的目标,不是吗?
  • @Yakk 是的,所以转发右值元组的左值引用成员应该产生一个左值。 (我相信std::get 已经处理了吗?)
  • nod,但以上不能:唯一的方法是在课堂“内部”并知道你是否拥有 TT&amp; ,因为在这两种情况下,任何明智的访问器都会返回T&amp;。我只是注意到,如果你有一个(不存在的)vector&lt;int&amp;&gt;,如果容器是一个右值,上面的内容将是move-from,并考虑是否有办法解决它。我没有看到一个。从根本上说,使forward_like&lt;U&gt; 比感知右值的访问器更弱。 rvalue-aware 访问器总是看起来很脏(你需要知道你并没有真的移动,只是移动那个字段)。
  • @Yakk 事实上,我们需要知道存储的东西是否实际上是一个引用,这意味着可以通过某种方式直接查询容器(tuple_element_t 使用元组;也许value_type 用于容器) .
猜你喜欢
  • 1970-01-01
  • 2019-04-16
  • 2015-03-03
  • 2019-07-09
  • 1970-01-01
  • 2013-11-16
  • 2021-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多