#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; | |
}; |
This comment has been minimized.
This comment has been minimized.
@come-raczy That's an incorrect behaviour. You cannot pass pointer to private member anywhere except the arguments for explicit instantiation. |
This comment has been minimized.
This comment has been minimized.
(Revised 13-Oct-2016!) This technique can also be used to access private static member variables. E.g. struct B
{
private:
static char const* x;
};
char const* B::x = "proof!";
struct B_x { typedef char const** type; };
template class stow_private<B_x,&B::x>;
int main()
{
// Use the stowed private static member pointer
std::cout << *stowed<B_x>::value << std::endl;
}; |
This comment has been minimized.
This comment has been minimized.
@dabrahams Just for fun, I tried a variation on the ideas from your code example using variable templates: |
This comment has been minimized.
This comment has been minimized.
@dabrahams what are lines 19 and 20 doing? As far as I understand, you declare a Why do you "repeat" the declaration on lines 19-20? It is not template specialization, because you still have the same template parameters... |
This comment has been minimized.
This comment has been minimized.
@ProExpertProg Sorry, this sample is almost a decade old; I don't remember. |
This comment has been minimized.
This comment has been minimized.
Lol no worries. I'll give it a try compiling it myself without those lines and post the error here for other future googlers. The explanations in the comments are great though! |
This comment has been minimized.
This comment has been minimized.
@ProExpertProg Line 17 is a declaration, whereas lines 19-20 provides the definition; the latter is key as it controls the initialization of the (singleton) static data member Or, in other simpler words, the definition at lines 19-20 is required such that the constructor of |
This comment has been minimized.
This comment has been minimized.
This makes sense, thank you! I forgot that static members in classes are just declarations and need definitions. |
This comment has been minimized.
why having several layers of classes and static members instead of a single class with static method like this:
It seems to work (at least with gcc 4.8.1 using c++11)