-
-
Save dabrahams/1528856 to your computer and use it in GitHub Desktop.
#include <iostream> | |
// This is a rewrite and analysis of the technique in this article: | |
// http://bloglitb.blogspot.com/2010/07/access-to-private-members-thats-easy.html | |
// ------- Framework ------- | |
// The little library required to work this magic | |
// Generate a static data member of type Tag::type in which to store | |
// the address of a private member. It is crucial that Tag does not | |
// depend on the /value/ of the the stored address in any way so that | |
// we can access it from ordinary code without directly touching | |
// private data. | |
template <class Tag> | |
struct stowed | |
{ | |
static typename Tag::type value; | |
}; | |
template <class Tag> | |
typename Tag::type stowed<Tag>::value; | |
// Generate a static data member whose constructor initializes | |
// stowed<Tag>::value. This type will only be named in an explicit | |
// instantiation, where it is legal to pass the address of a private | |
// member. | |
template <class Tag, typename Tag::type x> | |
struct stow_private | |
{ | |
stow_private() { stowed<Tag>::value = x; } | |
static stow_private instance; | |
}; | |
template <class Tag, typename Tag::type x> | |
stow_private<Tag,x> stow_private<Tag,x>::instance; | |
// ------- Usage ------- | |
// A demonstration of how to use the library, with explanation | |
struct A | |
{ | |
A() : x("proof!") {} | |
private: | |
char const* x; | |
}; | |
// A tag type for A::x. Each distinct private member you need to | |
// access should have its own tag. Each tag should contain a | |
// nested ::type that is the corresponding pointer-to-member type. | |
struct A_x { typedef char const*(A::*type); }; | |
// Explicit instantiation; the only place where it is legal to pass | |
// the address of a private member. Generates the static ::instance | |
// that in turn initializes stowed<Tag>::value. | |
template class stow_private<A_x,&A::x>; | |
int main() | |
{ | |
A a; | |
// Use the stowed private member pointer | |
std::cout << a.*stowed<A_x>::value << std::endl; | |
}; |
Here's a even more straightforward implementation, with better encapsulations & use cases:
https://github.com/YunHsiao/UnrealSourceInjector/blob/main/SourcePatch/Runtime/Core/Public/Misc/PrivateAccessor.h
@YunHsiao As of new C++20 rules (P0692R1) you can make this even more straightforward, using specialization instead of explicit instantiation definitions. See https://github.com/dfrib/accessprivate (companion article: A foliage of folly).
@dfrib Great write up on the subject, plus your usage of auto non-type template arguments feature yields much simpler declaration!
Although I'm writing a code injector for different versions of Unreal Engine here so C++14 back compat is a must :(
But besides that, afaic it was a perfectly valid usage of this, which provided some really interesting leverages for us.
This makes sense, thank you! I forgot that static members in classes are just declarations and need definitions.