I realized that it would be beneficial to have an alternative implementation because the previous code suffered from the Static Initialization Order Fiasco. The following code does not suffer from that problem anymore:
template<typename Tag, typename Tag::type M> struct Rob { friend typename Tag::type get(Tag) { return M; } };This defines a friend function that can be called by ADL using the tag type.
// use struct A { A(int a):a(a) { } private: int a; }; // tag used to access A::a struct A_f { typedef int A::*type; friend type get(A_f); }; template struct Rob<A_f, &A::a>; int main() { A a(42); std::cout << "proof: " << a.*get(A_f()) << std::endl; }Note that the explicit declaration of "get" inside of "A_f" is important, because we want "get" to be visible to ADL, and the rob template specialization is not an associated class of "A_f" (we could have declared it globally too, if we wanted, but then it would be visible for anyone). To overcome that, we could introduce some utility class we derive from:
template<typename Tag, typename Member> struct TagBase { typedef Member type; friend type get(Tag); };The definition of a Tag then becomes very simple
struct A_f : TagBase<A_f, int A::*> { };Unfortunately with the TagBase, GCC spits out a warning about the "friend type get(Tag)" that it declares a non-template function. The warning can be ignored, but it's annoying :).
Hope you enjoyed!