【问题标题】:Perfect forwarding a member of object完美转发对象成员
【发布时间】:2012-01-24 03:12:28
【问题描述】:

假设我有两个structs:

struct X {};
struct Y { X x; }

我有函数:

void f(X&);
void f(X&&);

如何编写一个函数g(),它接受Y&Y&&,但完美地将X&X&& 分别转发到f()

template <typename T>
void g(T&& t) {
  if (is_lvalue_reference<T>::value) {
    f(t.x);
  } else {
    f(move(t.x));
  }
}

上面的代码说明了我的意图,但随着参数数量的增加,它的可扩展性并不高。有没有办法让它完美转发并使其可扩展?

【问题讨论】:

  • 我认为将 is_lvalue_reference&lt;T&gt;::value 更改为 is_lvalue_reference&lt;decltype(std::forward&lt;T&gt;(t))&gt;::value 将具有您想要的语义,但我认为您想要的语义是有问题的......
  • (抱歉回答拙劣。)我想说它无法扩展的原因是因为设计一开始就有问题。 “移动”子对象是什么意思?这使主要对象处于什么状态?即使有一种简单的方法来编写它,它看起来也像是结构不佳的代码......

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


【解决方案1】:
template <typename T>
void g(T&& t) {
  f(std::forward<T>(t).x);
}

【讨论】:

  • @Pubby 因为rvalue.foo 是一个右值。我可以想到为什么它可能有意义(如果容器的生命周期很短并且是右值,则包含的对象也共享该属性),但我不熟悉哲学并且不知道基本原理,所以我对此无话可说。
  • rvalue.foo 实际上应该是一个 xvalue。
  • @curi 一些委员会成员这样说。但是,“右值”(对象表达式)有时保持纯右值的原因是什么?反对使成员选择成为一个 xvalue 的事实是它的动态类型与表达式的静态类型没有区别。
  • 这正是我正在寻找的答案。
  • 真是个天才!!
【解决方案2】:

我认为这会奏效,虽然我不确定:

template<class T, class M>
struct mforward {
  using type = M&&; 
};
template<class T, class M>
struct mforward<T&, M> {
  using type = M&; 
};

template <typename T>
void g(T&& t) {
  f(std::forward<typename mforward<T, decltype(t.x)>::type>(t.x));
}

【讨论】:

  • +1 我必须在 libc++ 中解决几乎这个确切的问题。我想出的解决方案看起来与 Pubby 的非常相似。我不仅想将T 的l/r 值“应用”到M,我还想将T 的cv 限定应用于M。我发现它的应用程序超出了数据成员。对于好奇的人,我称之为__apply_cv,它是开源代码:libcxx.llvm.org
  • @Howard 查看我的答案以寻找替代方案。还是我错过了什么?
  • 另外@Howard 谈论 cv 资格让我想到了这个答案的一个缺陷。 decltype(t.x) 只为您提供x 的声明类型。如果Tconst,但x 被声明为int a,那么您的转发器将尝试将事物转发为int&amp; / int&amp;&amp;。您需要说类似 typename remove_reference&lt;decltype((t.x))&gt;::type 的内容来考虑 t 的常量性。这也考虑了mutable 成员,但我不知道移动对于其他const 对象的可变成员在哲学上意味着什么。
  • @Johannes:我同意,你的解决方案看起来更适合这个用例。
  • @Howard:如果 Johannes 的解决方案行不通,而 __apply_cv 的解决方案行得通,那会是什么情况?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-20
  • 2018-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多