Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

A cool thing with C++ is that it lets you create variables of pointer-to-member types. The most common use case seems to be to get a pointer to a method:

struct foo
{
    int x() { return 5; }
};

int (foo::*ptr)() = &foo::x;
foo myFoo;
cout << (myFoo.*ptr)() << '\n'; // prints "5"

However, messing around, I realized that they can just as well point to member variables:

struct foo
{
    int y;
};

int foo::*ptr = &foo::y;
foo myFoo;
myFoo.*ptr = 5;
cout << myFoo.y << '\n'; // prints "5"

This is pretty rad. It led me to a further experiment: what if you could get a pointer to a sub-member of a structure?

struct foo
{
    int y;
};

struct bar
{
    foo aFoo;
};

int bar::*foo::*ptr;

This actually compiles.

However, I have no idea how to assign it anything useful. None of the following works:

int bar::*foo::*ptr = &bar::foo::y; // no member named "foo" in "bar"
int bar::*foo::*ptr = &bar::aFoo::y; // no member named "aFoo" in "bar" (??)
int bar::*foo::*ptr = &foo::y; // can't init 'int bar::*foo::*' with 'int foo::*'

Furthermore, according to the error that this generates, it appears that this type is not exactly what I have in mind:

int bar::*foo::*ptr = nullptr;
bar myBar;
myBar.*ptr = 4; // pointer to member type ‘int bar::*’ incompatible
                // with object type ‘bar’

It appears that this concept evades me. Obviously, I can't rule out that it simply gets parsed in a way entirely different from what I would expect.

Would anyone please explain me what an int bar::*foo::* actually is? Why does gcc tell me that a pointer to a member of bar is incompatible with a bar object? How would I use an int bar::*foo::*, and how would I construct a valid one?

like image 503
zneak Avatar asked Oct 05 '14 07:10

zneak


People also ask

What is int FOO in C?

int& foo(); is a function returning a reference to int . Your provided function returns int without reference.

What is FOO and bar in C++?

The terms foobar (/ˈfuːbɑːr/), foo, bar, baz, and others are used as metasyntactic variables and placeholder names in computer programming or computer-related documentation.

What is FOO in html?

Foo (pronounced FOO) is a term used by programmers as a placeholder for a value that can change, depending on conditions or on information passed to the program. Foo and other words like it are formally known as metasyntactic variables.

What is FOO and bar in Java?

It's a generic name for a thing, using in computer science in general. Etymologically, "foo" is the first syllable of "FUBAR", which is an acronym for "**ed Up Beyond All Recognition/Recovery". Follow this answer to receive notifications.


2 Answers

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;
like image 199
John Zwinck Avatar answered Oct 17 '22 05:10

John Zwinck


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);
}
like image 19
jrok Avatar answered Oct 17 '22 04:10

jrok