#pragma once /// The exposer can forcibly access private members of a class without changing /// any code. It uses macros to construct a function that returns a reference /// to the target member variable. namespace exposer { template struct Exposer { constexpr friend T fetch(Tag) { return Val; } }; } // namespace exposer #define COMBINE_IMPL(x, y) x##y #define HELPER(x) COMBINE_IMPL(Helper_, x) #define PROTO(x) COMBINE_IMPL(Proto_, x) #define FORCE_ACCESS_VAR_IMPL(Class, Type, Member, Tag) \ struct HELPER(Tag) {}; \ template struct Exposer; \ constexpr Type Class::* fetch(HELPER(Tag)); \ constexpr Type Class##_##Member(Class &&c) { \ return c.*fetch(HELPER(Tag){}); \ } \ constexpr Type& Class##_##Member(Class &c) { \ return c.*fetch(HELPER(Tag){}); \ } \ constexpr const Type& Class##_##Member(const Class &c) { \ return c.*fetch(HELPER(Tag){}); \ } #define FORCE_ACCESS_CONST_VAR_IMPL(Class, Type, Member, Tag) \ struct HELPER(Tag) {}; \ template struct Exposer; \ constexpr const Type Class::* fetch(HELPER(Tag)); \ constexpr Type Class##_##Member(Class &&c) { \ return c.*fetch(HELPER(Tag){}); \ } \ constexpr const Type& Class##_##Member(Class &c) { \ return c.*fetch(HELPER(Tag){}); \ } \ constexpr const Type& Class##_##Member(const Class &c) { \ return c.*fetch(HELPER(Tag){}); \ } #define FORCE_ACCESS_FUNC_IMPL(Class, Proto, Member, Tag) \ struct HELPER(Tag) {}; \ using PROTO(Tag) = Proto; \ template struct Exposer; \ constexpr PROTO(Tag) Class::* fetch(HELPER(Tag)); \ template \ requires std::is_same_v, Class> \ constexpr decltype(auto) Class##_##Member(C &&c, Args &&...args) { \ return (std::forward(c).*fetch(HELPER(Tag){}))(std::forward(args)...); \ } #define FORCE_ACCESS_CONST_FUNC_IMPL(Class, Proto, Member, Tag) \ struct HELPER(Tag) {}; \ using PROTO(Tag) = Proto const; \ template struct Exposer; \ constexpr PROTO(Tag) Demo::* fetch(HELPER(Tag)); \ template \ requires std::is_same_v>, Class> \ constexpr decltype(auto) Class##_##Member(C &&c, Args &&...args) { \ return (std::forward(c).*fetch(HELPER(Tag){}))(std::forward(args)...); \ } #define FORCE_ACCESS_STATIC_VAR_IMPL(Class, Type, Member, Tag) \ struct HELPER(Tag) {}; \ template struct Exposer; \ constexpr Type* fetch(HELPER(Tag)); \ constexpr Type& Class##_##Member() { \ return *fetch(HELPER(Tag){}); \ } #define FORCE_ACCESS_STATIC_CONST_VAR_IMPL(Class, Type, Member, Tag) \ struct HELPER(Tag) {}; \ template struct Exposer; \ constexpr const Type* fetch(HELPER(Tag)); \ constexpr const Type& Class##_##Member() { \ return *fetch(HELPER(Tag){}); \ } #define FORCE_ACCESS_STATIC_FUNC_IMPL(Class, Proto, Member, Tag) \ struct HELPER(Tag) {}; \ using PROTO(Tag) = Proto; \ template struct Exposer; \ constexpr PROTO(Tag)* fetch(HELPER(Tag)); \ template \ constexpr decltype(auto) sfunc(Args &&...args) { \ return fetch(HELPER(Tag){})(std::forward(args)...); \ } #define FORCE_ACCESS_VAR(Class, Type, Member) \ namespace exposer { \ FORCE_ACCESS_VAR_IMPL(Class, Type, Member, __COUNTER__) \ } #define FORCE_ACCESS_CONST_VAR(Class, Type, Member) \ namespace exposer { \ FORCE_ACCESS_CONST_VAR_IMPL(Class, Type, Member, __COUNTER__) \ } #define FORCE_ACCESS_FUNC(Class, Proto, Member) \ namespace exposer { \ FORCE_ACCESS_FUNC_IMPL(Class, Proto, Member, __COUNTER__) \ } #define FORCE_ACCESS_CONST_FUNC(Class, Proto, Member) \ namespace exposer { \ FORCE_ACCESS_CONST_FUNC_IMPL(Class, Proto, Member, __COUNTER__) \ } #define FORCE_ACCESS_STATIC_VAR(Class, Type, Member) \ namespace exposer { \ FORCE_ACCESS_STATIC_VAR_IMPL(Class, Type, Member, __COUNTER__) \ } #define FORCE_ACCESS_STATIC_CONST_VAR(Class, Type, Member) \ namespace exposer { \ FORCE_ACCESS_STATIC_CONST_VAR_IMPL(Class, Type, Member, __COUNTER__) \ } #define FORCE_ACCESS_STATIC_FUNC(Class, Proto, Member) \ namespace exposer { \ FORCE_ACCESS_STATIC_FUNC_IMPL(Class, Proto, Member, __COUNTER__) \ }