接受左值ref或rvalue ref

时间:2014-10-28 14:29:24

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

我想编写一些以Object作为其参数之一的函数,无论是通过左值还是右值ref都不重要 - 但绝对不是按值而且绝对只是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
}

但是第一个选项涉及编写两倍于我需要的函数,第二个选项涉及编写一堆模板内容,这对我来说似乎有点过分(我有点认为接受任何东西 o - 哦开玩笑,真的只是Object)。

有没有更好的方法可以解决这个问题,或者我只是坚持使用其中任何一种我觉得不那么简单的方法?

2 个答案:

答案 0 :(得分:6)

两种实现之间存在差异。第一个允许任何可转换为ObjectObject&&Object&的内容。第二个只会承认Object以及以rvalue或左值形式从中继承的东西(并拒绝const Object s,就像第一个一样)。

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

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->或执行Object& o = o_;才能获得原始参考。

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

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

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

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

在需要时将rvalues转换为左值(你也可以称之为unmove可爱)

答案 1 :(得分:4)

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