如何判断Base类成员函数中this或参数other是否为rvalue?
嘿,我明白你的困扰——不想用模板友元,又要在成员函数里判断this和other是不是右值对吧?别担心,有几种更合适的方案,我给你详细讲:
方案1:用引用限定符+参数重载,直接区分所有情况
这是最贴合C++设计风格的做法,完全不需要模板友元,靠函数重载就能明确知道this和other的左右值属性:
#include <utility> class Base { public: // 场景1:调用当前对象是左值,other是左值 Base doSomething(const Base& other) & { // 这里*this是左值,不能随便移动它的资源 // 按左值逻辑处理即可 return Base{}; // 示例返回,按需修改 } // 场景2:调用当前对象是左值,other是右值 Base doSomething(Base&& other) & { // other是右值,可以安全移动它的资源 return std::move(other); } // 场景3:调用当前对象是右值,other是左值 Base doSomething(const Base& other) && { // *this是右值,放心移动它的资源 return std::move(*this); } // 场景4:调用当前对象是右值,other是右值 Base doSomething(Base&& other) && { // 两个都是右值,选一个优先移动就行(看你的业务逻辑) return std::move(*this); // 或者std::move(other) } // 其他成员变量和函数... };
这种方案的优势是代码逻辑一目了然,每个重载函数对应一种明确的场景,不需要在函数内部做额外判断,而且完全是类的成员函数,不用牵扯友元或者外部模板。
方案2:用内部模板减少重复代码
如果四个重载里有大量重复逻辑,你可以把公共逻辑抽到类内的模板函数里,避免代码复制:
#include <utility> #include <type_traits> class Base { public: // 对外暴露的左值调用接口 Base doSomething(const Base& other) & { return doSomethingImpl(other, *this); } Base doSomething(Base&& other) & { return doSomethingImpl(std::move(other), *this); } // 对外暴露的右值调用接口 Base doSomething(const Base& other) && { return doSomethingImpl(other, std::move(*this)); } Base doSomething(Base&& other) && { return doSomethingImpl(std::move(other), std::move(*this)); } private: // 内部模板实现,用来统一处理所有场景 template<typename Other, typename Self> Base doSomethingImpl(Other&& other, Self&& self) { // 编译期判断:当前对象(self)是不是右值 if constexpr (std::is_rvalue_reference_v<Self&&>) { // 处理右值this的逻辑,比如移动资源 return std::move(self); } // 编译期判断:other是不是右值 else if constexpr (std::is_rvalue_reference_v<Other&&>) { // 处理右值other的逻辑 return std::move(other); } // 两个都是左值的情况 else { return Base{}; } } // 其他成员变量和函数... };
这里用了C++17的if constexpr在编译期做类型判断,没有运行时开销,而且内部模板只在类内可见,完全符合你不想用外部模板友元的要求。
补充说明:为什么不能直接在普通成员函数里判断?
要注意:如果你的成员函数没有加引用限定符(&或&&),不管调用者是左值还是右值,函数内部的*this都会被当成左值,这时候你没法直接判断原对象是不是右值。所以必须用引用限定符来区分调用场景,这是C++标准的规定。
另外,对于other参数,如果它是const Base&类型,你没法直接判断它绑定的是左值还是右值——因为const左值引用可以绑定任何表达式。所以要区分other的左右值,必须给参数做重载:一个用const Base&接收左值,一个用Base&&接收右值,这样在重载函数里就明确知道other的类型了。
内容的提问来源于stack exchange,提问作者defo900
相关产品推荐
相关产品推荐

