我想编写一些以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
)。
有没有更好的方法可以解决这个问题,或者我只是坚持使用其中任何一种我觉得不那么简单的方法?
答案 0 :(得分:6)
两种实现之间存在差异。第一个允许任何可转换为Object
,Object&&
或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。您必须访问*o
和o->
或执行Object& o = o_;
才能获得原始参考。
它不像第一个解决方案,因为C ++不链接两个用户定义的转换。
概念提案会增加说“我在这里拿任何东西,只要它是Object
”并且语法更简洁的能力。
另一种方法是采用Object&
,然后使用:
tepmlate<class T>
T& lvalue( T&& t) { return t; }
在需要时将rvalues转换为左值(你也可以称之为unmove
可爱)
答案 1 :(得分:4)
接受左值和右值的典型方法是创建一个带有const引用的函数。这意味着你不能在对象上调用非const函数,但是如果你想传递诸如临时函数之类的rvalues,那么无论如何调用非const函数都不是很有意义。