如何以最简方式编写自由函数获取C++类的公有成员?
实现与直接访问成员语义完全一致的
getBar函数 这个问题源于对另一Stack Overflow问题及其解答的思考。
假设有一个无法修改的类Foo,它拥有一个public成员bar,但没有对应的getter方法。我们需要编写一个getBar函数,使得getBar(expr-of-type-Foo)与expr-of-type-Foo.bar的语义完全一致——无论传入的expr-of-type-Foo是Foo类型的prvalue、xvalue还是lvalue。
给定的Foo定义如下:
struct Foo { int bar{}; ~Foo() { bar = -1; } // 在多数编译器中,这有助于"验证"对象已销毁 };
初始实现
我最初的实现方案是通过重载处理不同值类别的输入,借助boost::hana::overload来组合重载逻辑:
constexpr auto getBar = overload( [](auto& foo) -> decltype(auto) { return (foo.bar); }, [](auto const& foo) -> decltype(auto) { return (foo.bar); }, [](auto&& foo) -> auto { return foo.bar; } );
注:-> auto是冗余的,但在此场景下更具说明性。
简化思路
我尝试对初始实现进行简化,逐步优化:
第一步:明确引用返回类型
既然auto&/auto const&重载分别匹配非const左值和const左值,我们可以把返回类型从decltype(auto)改为明确的引用类型,同时去掉return表达式的括号:constexpr auto getBar = overload( [](auto& foo) -> auto& { return foo.bar; }, [](auto const& foo) -> auto const& { return foo.bar; }, [](auto&& foo) -> auto { return foo.bar; } );第二步:合并左值重载
进一步思考后发现,auto&重载无法匹配const左值,此时const左值会自然匹配到对应重载,因此可以简化为只保留两个重载:auto&处理非const左值,auto&&处理右值和const左值,此时返回值的语义依然和直接访问bar一致:constexpr auto getBar = overload( [](auto& foo) -> auto& { return foo.bar; }, [](auto&& foo) -> auto { return foo.bar; } );
目前我想不到进一步简化的方法。
测试代码
以下是验证上述实现的测试代码:
#include<assert.h> #include<boost/hana/functional/overload.hpp> struct Foo { int bar{}; ~Foo() { bar = -1; } }; int main() { { constexpr auto getBar = overload( [](auto&& foo) -> auto { return foo.bar; }, [](auto& foo) -> auto& { return foo.bar; } ); { Foo foo{3}; assert(&getBar(foo) == &foo.bar); assert(getBar(foo) == 3); foo.bar = 4; assert(foo.bar == 4); assert(getBar(foo) == 4); getBar(foo) = 5; assert(foo.bar == 5); assert(getBar(foo) == 5); } { Foo const foo{3}; assert(&getBar(foo) == &foo.bar); assert(getBar(foo) == 3); //foo.bar = 3; // 预期编译失败 //getBar(foo) = 3; // 预期编译失败 } { auto const& foobar = getBar(Foo{3}); assert(foobar == 3); //foobar = 5; // 预期编译失败 } { //auto& foobar = getBar(Foo{3}); // 预期编译失败 //auto& foobar = Foo{3}.bar; // 预期编译失败 } } }
内容的提问来源于stack exchange,提问作者Enlico
相关产品推荐
相关产品推荐

