【问题标题】:Accept lvalue ref or rvalue ref接受左值引用或右值引用
【发布时间】:2014-10-28 14:29:23
【问题描述】:

我想编写一些将Object 作为参数之一的函数,无论是左值还是右值引用都无关紧要——但绝对不是值,而且绝对只有Object。看来我有两种选择:

void foo(Object& o) {
    // stuff
}

void foo(Object&& o) { foo(o); } // this is fine for my use-case

或者使用通用引用:

template <typename T, typename U>
using decays_to = typename std::is_same<std::decay_t<T>, U>::type;

template <typename T>
std::enable_if_t<decays_to<T, Object>::value>
foo(T&& o) 
{
    // same stuff as before
}

但第一个选项涉及编写两倍于我需要的函数,而第二个选项涉及编写一堆模板内容,这对我来说似乎有点过头了(我读到接受 anything 对于o - 哦,开个玩笑,真的只是Object)。

有没有更好的方法来解决这个问题,或者我只是坚持使用我觉得不那么无聊的任何一个?

【问题讨论】:

  • void foo(Object const&amp; o) 就够了吗?它将接受右值和左值,但它是const
  • @Niall 哇。它完全会。有时,我显然是想太多了。
  • std::remove_const_t&lt;std::remove_reference_t&lt;T&gt;&gt; 将是比 std::decay_t&lt;T&gt; 更好的选择,因为 decay_t 具有执行函数到指针和数组到指针转换的副作用。

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


【解决方案1】:

您的两个实现之间存在差异。第一个将允许任何可转换为ObjectObject&amp;&amp;Object&amp; 的内容。第二个只会接受Object 以及以右值或左值形式从它继承的东西(并拒绝const Objects,就像第一个一样)。

我们可以添加一个辅助对象:

template<class T>
struct l_or_r_value {
  T& t;
  l_or_r_value( T&& t_ ):t(t_) {}
  l_or_r_value( T& t_ ):t(t_) {}
  operator T&(){ return t; }
  T* operator->(){ return &t; }
  T& operator*(){ return t; }
  T& get(){ return t; }
};

那么我们可以写:

void foo(l_or_r_value<Object> o)

我们得到的行为与您的第二个解决方案非常接近,在调用点没有模板 mumbo jumbo。您必须访问 *oo-&gt; 或执行 Object&amp; o = o_; 才能获得原始参考。

它不像第一个解决方案,因为 C++ 没有链接两个用户定义的转换。

概念提案将增加使用更简洁的语法说“我在这里拿任何东西,只要它是Object”的能力。

另一种方法是使用Object&amp;,然后使用:

tepmlate<class T>
T& lvalue( T&& t) { return t; }

在需要时将右值转换为左值(您也可以称其为unmove 以表示可爱)

【讨论】:

  • 我真的很喜欢这个答案 - 并且可能会在某个地方使用 l_or_r_value - 但我接受另一个只是因为它对我的用例更直接。
  • @Barry 啊!抱歉,我认为您实际上是想修改函数中的值,而拒绝 const 对象是故意的。
  • 不,只是因为键盘和椅子之间存在问题而拒绝它们。
【解决方案2】:

同时接受左值和右值的典型方法是创建一个接受 const 引用的函数。这意味着您不能在对象上调用非常量函数,但是如果您想传递诸如临时值之类的右值,那么调用非常量函数无论如何都没有多大意义。

【讨论】:

    猜你喜欢
    • 2017-12-03
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-03
    相关资源
    最近更新 更多