What is an `int foo::*bar::*`?

Here's a "valid" way of initializing such a monstrosity:

struct bar;

struct foo
{
    int y;    
    int bar::* whatever;
};

struct bar
{
    foo aFoo;
};

int bar::* foo::* ptr = &foo::whatever;

As we can see, ptr is a pointer to a member of foo (foo::*, reading right to left), where that member is itself a pointer to a member of bar (bar::*), where that member is an int.

How would I use an int bar::* foo::*

You wouldn't, hopefully! But if you are under duress, try this!

struct bar
{
    foo aFoo;

    int really;
};

int bar::* foo::* ptr = &foo::whatever;
foo fleh;
fleh.whatever = &bar::really;
bar blah;
blah.*(fleh.*ptr) = 42;
std::cout << blah.really << std::endl;

That would be a pointer to a data member that is itself a pointer to a data member (an int member of bar).

Don't ask me what it is actually useful for - my head is spinning a little :)

EDIT: Here's a full example of it in action:

#include <iostream>

struct bar {
    int i;
};

struct foo {
    int bar::* p;
};

int main()
{
    bar b;
    b.i = 42;

    foo f;
    f.p = &bar::i;

    int bar::*foo::*ptr = &foo::p;
    std::cout << (b.*(f.*ptr));
}

Output is, of course, 42.

It can get even more fun - here's some pointers to member functions that return pointers to member functions:

#include <iostream>

struct bar {
    int f_bar(int i) { return i; };
};

struct foo {
    int(bar::*f_foo())(int)
    {
        return &bar::f_bar;
    }
};

int main()
{
    int(bar::*((foo::*ptr)()))(int) = &foo::f_foo;

    bar b;
    foo f;

    std::cout << (b.*((f.*ptr)()))(42);
}

Let's parse the declaration int bar::*foo::*ptr;.

§8.3.3 [dcl.mptr]/p1:

In a declaration T D where D has the form

nested-name-specifier * attribute-specifier-seq_opt cv-qualifier-seq_opt D1

and the nested-name-specifier denotes a class, and the type of the identifier in the declaration T D1 is “derived-declarator-type-list T”, then the type of the identifier of D is “derived-declarator-type-list cv-qualifier-seq pointer to member of class nested-name-specifier of type T”.

  • Step 1: This is a declaration of the above form where T = int, nested-name-specifier = bar::, and D1 = foo::* ptr. We first look at the declaration T D1, or int foo::* ptr.

  • Step 2: We apply the same rule again. int foo::* ptr is a declaration of the above form where T = int, nested-name-specifier = foo::, and D1 = ptr. Obviously the type of the identifier in int ptr is "int", so the type of the identifier ptr in the declaration int foo::* ptr is "pointer to member of class foo of type int".

  • Step 3. We go back to the original declaration; the type of the identifier in T D1(int foo::* ptr) is "pointer to member of class foo of type int" per step 2, so the derived-declarator-type-list is "pointer to member of class foo of type". Substitution tells us that this declaration declares ptr to be "pointer to member of class foo of type pointer to member of class bar of type int".

Hopefully you will never need to use such a monstrosity.


In case anyone is wondering, you can't create a pointer-to-member which nests multiple layers deep. The reason for this is that all pointer-to-members are actually way more complicated that what they look at a first glance; they are not simply containing a particular offset for that specific member.

Using a simple offset does not work due to virtual inheritance and the likes; basically it can happen that, even within a single type, the offsets of a particular field vary between instances, and thus pointer-to-member resolution needs to be done at runtime. Mostly this is due to the fact that the standard does not specify how the internal layout for non-POD types might work, so there's no way to make it work statically.

If this is the case, doing two-level deep resolution cannot be done with a normal pointer-to-member, but would need the compiler to generate a pointer such that it contains double the information of a one-deep pointer-to-member.

I imagine that since pointers-to-member are not that common, there is no need to actually create a syntax to allow for setting multiple-layer deep members, when you can still use multiple pointers to achieve the same result.