了解'this'或其他参数是否为右值

get know whether 'this' or other arguments are rvalue

本文关键字:是否 this 了解 其他 参数      更新时间:2023-10-16

假设我们有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"重值">