7

I asked a question while ago about accessing the underlying container of STL adapters. I got a very helpful answer:

template <class T, class S, class C>
    S& Container(priority_queue<T, S, C>& q) {
        struct HackedQueue : private priority_queue<T, S, C> {
            static S& Container(priority_queue<T, S, C>& q) {
                return q.*&HackedQueue::c;
            }
        };
    return HackedQueue::Container(q);
}

int main()
{
    priority_queue<SomeClass> pq;
    vector<SomeClass> &tasks = Container(pq);
    return 0;
}

Unfortunately, I couldn't understand this line:

return q.*&HackedQueue::c;

What does this line do? Also, how could that line access the private container in priority_queue that is passed to the function Container?

Community
  • 1
  • 1
Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234

1 Answers1

13

Think of it like this:

(q).*(&HackedQueue::c);

First, you have HackedQueue::c, which is just the name of a member variable. Then you take &HackedQueue::c, which is a pointer to that member variable. Next you take q, which is just an object reference. Then you use the "bind pointer to member by reference" operator .* to bind the member variable referred to by the member-variable pointer using q as the this.

As to the private member issue, priority_queue::c is only protected, not private, so it should come as no surprise that when you derive from priority_queue, that you can access its protected members.

Khaled Alshaya
  • 94,250
  • 39
  • 176
  • 234
Eclipse
  • 44,851
  • 20
  • 112
  • 171
  • Thanks but 'c' is a member variable. Which is the container inside the std::priority_queue. – Khaled Alshaya Sep 09 '09 at 17:08
  • Sorry, yes. It's a member variable, but the bind to member operator is still the same (just like `.` gets used for both jobs. – Eclipse Sep 09 '09 at 17:12
  • 4
    `&(HackedQueue::c)` will actually try to get a pointer to the member variable, and fail because c is not a static member. Common pit-fall :) Between the & and the member name cannot be anything except whitespace. for example: `struct A { int a; }; struct B : A { void f() { *&(A::a) = 0; this->*&A::a = 0; } };` Notice the difference: `&(A::a)` gets an int* to the actual member object (it's sometimes useful if a is hidden by a same name in the derived class), while `(&A::a)` gets a member pointer that stores the member offset. Anyway i understand it probably wasn't meant to be real code :) – Johannes Schaub - litb Sep 09 '09 at 22:21