假设我们有class Base及其成员函数 BasedoSomething(const Base&other(。我想知道如何确定这个或其他对象是否是右值, 例如,我需要类似的东西
Base Base::doSomething(const Base& other) {
...
if(this_is_rvalue) {
// use resources of *this
}
else if(other_is_rvalue) {
// use resources of other
}
...
}
我知道可能的解决方案是使用模板化的朋友函数:
template<typename T1, typename T2, typename = typename std::enable_if<.....>::type>
friend Base doSomething(T1&& this_, T2&& other) {
...
if(std::is_rvalue_reference<T1&&>::value) {
// use resources of this_
return std::move(this_);
}
else if(std::is_rvalue_reference<T2&&>::value) {
// use resources of other
return std::move(other);
}
}
但是,在我的情况下,这种方法是非常不可取
的提前感谢!
您可以使用 4 个重载来执行此操作:
Base Base::doSomething(Base& other) && {
// *this is an rvalue and other is an lvalue
}
Base Base::doSomething(Base&& other) && {
// *this and other are rvalues
}
Base Base::doSomething(Base& other) & {
// *this and other are lvalues
}
Base Base::doSomething(Base&& other) & {
// *this is an lvalue and other is an rvalue
}
如果您希望能够接受const Base
,那么您可以制作这些模板并使用 SFINAE 来确保衰减的模板类型是这样的Base
template <typename T, std::enable_if_t<std::is_same_v<std::decay_t<T>, Base>, bool> = true>
Base Base::doSomething(T& other) && {
// *this is an rvalue and other is an lvalue
}
Base Base::doSomething(Base&& other) && {
// *this and other are rvalues
}
template <typename T, std::enable_if_t<std::is_same_v<std::decay_t<T>, Base>, bool> = true>
Base Base::doSomething(T& other) & {
// *this and other are lvalues
}
Base Base::doSomething(Base&& other) & {
// *this is an lvalue and other is an rvalue
}
另一种方法是仅使用两个重载和转发引用。 然后,您可以检查参数的类型是否为左值引用,以确定您是具有左值还是右值。 这在使用转发引用时有效,因为模板参数的类型被推断为T&
而不是T
如果它是右值。 那会给你这样的代码
template<typename A, typename B, typename C>
Base Base::doSomething(A&& other1, B&& other2, C&& other3) &
{
// this is always an lvalue in this function
if (std::is_lvalue_reference_v<A>)
// other1 is an lvalue
else
// other1 is a rvalue
if (std::is_lvalue_reference_v<B>)
// other2 is an lvalue
else
// other2 is a rvalue
if (std::is_lvalue_reference_v<C>)
// other3 is an lvalue
else
// other3 is a rvalue
}
template<typename A, typename B, typename C>
Base Base::doSomething(A&& other1, B&& other2, C&& other3) &&
{
// this is always an rvalue in this function
if (std::is_lvalue_reference_v<A>)
// other1 is an lvalue
else
// other1 is a rvalue
if (std::is_lvalue_reference_v<B>)
// other2 is an lvalue
else
// other2 is a rvalue
if (std::is_lvalue_reference_v<C>)
// other3 is an lvalue
else
// other3 is a rvalue
}
然后,如果需要,您可以通过添加来约束模板
std::enable_if_t<std::is_same_v<std::decay_t<A>, type_for_other1>,
std::is_same_v<std::decay_t<B>, type_for_other2>,
std::is_same_v<std::decay_t<B>, type_for_other3>, bool> = true
到模板参数,将模板限制为所需的参数类型。
到每一个
这是您区分左值this
和右值this
的方式:
Base Base::doSomething(const Base& other) const &
// ^^^^^^^ lvalue only
Base Base::doSomething(const Base& other) &&
// ^^ rvalue only
这是区分左值输入和右值输入的方式,通常:
Base Base::doSomething(const Base& other) {
// use resources of *this
}
Base Base::doSomething(Base&& other) {
// use resources of other
}
听起来你想要两者的某种结合,所以也许:
Base Base::doSomething(Base&&) const &;
Base Base::doSomething(const Base&) &&;
不过,这让我觉得有点奇怪。考虑一下你是否真的走在正确的道路上。
来自 https://en.cppreference.com/w/cpp/language/member_functions
非静态成员函数可以在没有 ref-qualifier、lvalue ref-qualifier(参数列表后的标记和(或 rvalue ref-qualifier(参数列表后的标记 &&(的情况下声明。在重载解析期间,X 类的非静态 cv 合格成员函数的处理方式如下:
- 无 ref 限定符:隐式对象参数具有对 cv 限定 X 的类型 lvalue 引用,并且还允许绑定 rvalue 隐含对象参数
- 左值引用限定符:隐式对象参数具有对 cv 限定 X 的右值引用类型
- 右值引用限定符:隐式对象参数具有对 cv 限定的 X 的右值类型引用
因此,如果您这样做:
Base Base::doSomething(const Base& other) &&;
此函数将被调用this
"重值">