如何让调用const成员函数时自动触发Y的const版operator->?
实现调用const成员函数时自动触发const版本的operator->
原始问题代码
struct X { void foo () {} void const_foo () const {} }; struct Y { X x; int i; X* operator-> () { return &x; } const X* operator-> () const { return &x; } }; int main () { Y y; y->foo(); // 调用 Y::operator-> y->const_foo(); // 仍然调用 Y::operator->,但希望触发 Y::operator-> const!! }
如上述代码所示,希望在调用X的const成员函数(如const_foo())时,自动触发Y的const版本operator->,且不希望在调用处使用显式转换(如const_cast<const Y&>(y)->const_foo())。允许修改X/Y的内部实现、使用模板或调整对象声明方式,但调用语法需保持简洁。
可行方案:代理类+SFINAE判断成员函数const性
通过给Y的operator->返回一个代理对象,利用SFINAE(替换失败不是错误)技术判断后续调用的成员函数是否为const类型,从而决定触发Y的const或非const逻辑。这种方案需要调整调用语法为y->*&X::func(),但能满足自动触发的需求:
#include <type_traits> // 辅助模板:判断成员函数是否为const类型 template <typename MemFunc> struct is_const_member_func : std::false_type {}; template <typename Ret, typename Class, typename... Args> struct is_const_member_func<Ret (Class::*)(Args...) const> : std::true_type {}; template <typename MemFunc> constexpr bool is_const_member_func_v = is_const_member_func<MemFunc>::value; struct X { void foo () {} void const_foo () const {} }; struct Y { X x; int i; // 代理类:处理成员函数调用的分发 struct Proxy { Y* self; // 处理非const成员函数 template <typename MemFunc> auto operator->*(MemFunc func) -> std::enable_if_t<!is_const_member_func_v<MemFunc>, decltype((std::declval<X&>().*func)())> { // 这里执行非const版本的额外逻辑 return (self->x.*func)(); } // 处理const成员函数 template <typename MemFunc> auto operator->*(MemFunc func) -> std::enable_if_t<is_const_member_func_v<MemFunc>, decltype((std::declval<const X&>().*func)())> { // 这里执行const版本的额外逻辑(比如你需要的自定义代码) const Y& const_self = *self; return (const_self.x.*func)(); } // 处理数据成员访问(可选) template <typename Data> Data& operator->*(Data X::*data) { return self->x.*data; } template <typename Data> const Data& operator->*(Data X::*data) const { const Y& const_self = *self; // 数据成员的const访问逻辑 return const_self.x.*data; } }; // Y的非const operator->返回代理对象 Proxy operator->() { return {this}; } // Y的const operator->保留,供const Y对象使用 const X* operator->() const { // const对象的额外逻辑 return &x; } }; int main () { Y y; y->*&X::foo(); // 触发Y的非const逻辑 y->*&X::const_foo(); // 自动触发Y的const逻辑 }
保持原调用语法的非标准方案(GCC扩展)
如果必须保持y->func()的调用语法,可以使用GCC的operator.重载扩展(非标准特性)。通过代理类重载operator.,直接捕获要调用的成员函数并判断其const性:
#include <type_traits> struct X { void foo () {} void const_foo () const {} }; struct Y { X x; int i; struct Proxy { Y* self; // GCC扩展:重载operator. template <typename T> auto operator.*(T mem) -> decltype(std::declval<X&>().*mem) { if constexpr (is_const_member_func_v<decltype(mem)>) { const Y& const_self = *self; // const成员函数的额外逻辑 return const_self.x.*mem; } else { // 非const成员函数的逻辑 return self->x.*mem; } } }; Proxy operator->() { return {this}; } const X* operator->() const { return &x; } }; int main () { Y y; y->foo(); // 非const逻辑 y->const_foo(); // 自动触发const逻辑 }
注意:该方案依赖GCC编译器扩展,不具备跨编译器兼容性。
内容的提问来源于stack exchange,提问作者iammilind
相关产品推荐
相关产品推荐

