typedef std::queue Q;
Q
is a queue
adapted container.
typedef Q::container_type C;
C
is the underlying container of the Q
-- which is a deque
.
C & get (Q &q) {
get
takes a queue
and returns a deque
. In fact it returns the deque
that the queue
wraps: by conventional means, this is not possible.
struct hack : private Q {
hack
is a type local to the function. It inherits from Q
and has only one static member function. From its name, you may suspect it is a hack. You are right.
No hack
is ever instantiated.
static C & get (Q &q) {
hack::get
has the same signature as get
itself. In fact we delegate all of the work of get
to this method.
return q.*&hack::c;
this line needs to be broken down. I will do it in more lines:
using mem_ptr_t = C Q::*; // aka typedef C Q::*mem_ptr_t;
mem_ptr_t c_mem_ptr = &hack::c;
C& ret = q.*c_mem_ptr;
return ret;
The first line defines the type of a member pointer to a field of type C
within a Q
. Both the C++11 and C++03 ways of naming this type are ugly.
The second line gets a member pointer to the field c
in Q
. It does this through the hole in the type system of C++. &hack::c
is logically of type C hack::*
-- a pointer to a member of type C
within a class of type hack
. In fact, that is why we can access it in a static
member of hack
. But the c
in question is actually in Q
, so the actual type of the expression in C++ is C Q::*
: a pointer to a member variable of Q
.
You cannot directly get this member pointer within hack
-- &Q::c
is illegal, but &hack::c
is not.
You can think of member pointers as 'typed offsets' into another type: &hack::c
is the "offset" of c
within Q
together with knowing it is of type C
. Now this isn't really true -- it is some opaque value that tells the compiler how to get c
from Q
-- but it helps to think about it that way (and it may be implemented that way in simple cases).
We then use this member pointer together with a Q&
to get the c
out of the Q
. Getting a member pointer is constrained by protected: using it is not! The way we do it is with operator .*
, which is the member dereference operator, which you can pass either member function pointers or members on the right, and class instances on the left.
instance .* member_ptr
is an expression that finds the member "pointed to" by member_ptr
within the instance
. In the original code, everything was done on one line:
instance .* &class_name::member_name
so it looked like there was an operator .*&
.
}
};
and then we close up the static method and hack
class, and:
return hack::get(q);
}
call it. This technique gives access to protected
state: without it, protected
members can only be accessed in child classes of the same instance. Using this, we can access protected
members of any instance, without violating any bit of the standard.