What does the "=!" operator do?

typedef std::queue<int> Q;

Q is a queue adapted container.

typedef Q::container_type C;

C is the underlying container of the Q -- which is a deque<int>.

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.


It's a hack, as the nomenclature indicates.

.* takes an object on the left side, and a member pointer on the right side, and resolves the pointed-to member of the given object. & is, of course, the referencing operator; &Class::Member returns a member pointer, which cannot by itself be dereferenced but which can be used with the .* and ->* operators (the latter being the wackiest of all C++ operators). So obj .* &Class::Member has exactly the same effect as obj.Member.

The reason this more complicated version is being used comes down to a loophole in protection semantics; basically, it allows access to protected members of a base class object, even if the object is not of the same type as the class doing this dirty hack.

Personally, I think the trick is too clever by half. I'd ordinarily* write such code as:

struct hack : private Q {
    static C & get (Q &q) {
        return static_cast<hack &>(q).c;
    }
};

Which is technically slightly less safe, but doesn't obscure what's going on.

.* Well, ordinarily I'd avoid writing such a thing at all. But I literally did this earlier today, so I can't really throw stones.

Tags:

C++

C

Operators