C++中如何一次性删除类的所有右值成员函数重载?
如何一次性禁止类的右值实例调用成员函数
核心结论
截至C23标准,没有原生语法可以直接批量删除类的所有右值引用限定成员函数重载,但可以根据项目使用的C版本选择对应方案,实现和手动为每个成员编写void xxx() && = delete完全等价的约束效果,配合[[nodiscard]]属性即可强制调用方捕获函数返回的类实例。
方案1:C++23及以上版本(零重复代码,真正一次性拦截)
C++23新增了可重载的成员访问运算符operator.,你只需要删除右值版本的该运算符,就可以拦截所有右值、const右值实例上的成员访问操作,完全不需要逐个修改每个成员函数的重载声明:
struct no_can_rvalue { // 正常编写左值版本的成员函数即可,无需额外处理右值重载 void f() &; void g() &; int calc(int a, int b) &; private: // 拦截所有右值、const右值上的成员访问,直接触发编译错误 auto operator.() && = delete; auto operator.() const && = delete; // 左值、const左值的成员访问正常放行 auto& operator.() & { return *this; } auto& operator.() const& { return *this; } }; // 配合nodiscard属性,不捕获返回值直接丢弃也会触发编译警告 [[nodiscard]] no_can_rvalue a_func();
使用效果验证:
int main() { a_func(); // 触发[[nodiscard]]警告 a_func().f(); // 触发编译错误:右值operator.被删除 auto obj = a_func(); // 合法,捕获返回值 obj.f(); // 合法,左值实例可以正常调用成员 }
方案2:C++17/20兼容版本(低重复)
如果项目使用的C版本不支持C23的operator.重载,没有完美的零重复方案,最简洁的实现方式是通过封装宏减少重复代码,避免手动为每个成员写两次声明:
// 统一生成"右值删除、左值放行"的成员重载 #define LVALUE_MEMBER(RetType, FuncName, ...) \ RetType FuncName(__VA_ARGS__) && = delete; \ RetType FuncName(__VA_ARGS__) & struct no_can_rvalue { LVALUE_MEMBER(void, f, ); LVALUE_MEMBER(void, g, ); LVALUE_MEMBER(int, calc, int a, int b); }; [[nodiscard]] no_can_rvalue a_func();
该方案的效果和手动编写每个&& = delete的代码完全一致,只是通过宏减少了重复书写的工作量。
避坑提示
不要尝试通过删除类的移动构造函数、析构函数实现该约束:
- 删除移动构造会破坏C++的返回值优化机制,导致函数返回类实例时无法正常构造
- 析构函数不支持引用限定符,且删除析构函数会导致类完全无法实例化使用
内容的提问来源于stack exchange,提问作者scx
相关产品推荐
相关产品推荐

