1

Given a class instance and pointer to a field we can obtain regular pointer pointing to field variable of this class instance - as in last assignment in following code;

class A
{
public:
    int i, j;
};
int main(){
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;
}

Is it possible to invert this conversion: given class instance A a; and int* r obtain int A::* p (or NULL ptr if pointer given is not in instance given) as in code:

class A
{
public:
    int i, j;
};
int main(){
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;
    int A::*s = // a--->r -how to extract r back to member pointer?
}

The only way that I can think of doing it, would be to write a function that takes every known field of A, calculates it's address for given instance and compares with address given. This however requires writing custom code for every class, and might get difficult to manage. It has also suboptimal performance.

I can imagine that such conversion could be done by compiler in few operations under all implementations i know - such pointer is usually just an offset in structure so it would be just a subtraction and range check to see if given pointer is actually in this class storage. Virtual base classes add a bit of complexity, but nothing compiler couldn't handle I think. However it seems that since it's not required by standard (is it?) no compiler vendor cares.

Or am I wrong, and there is some fundamental problem with such conversion?

EDIT:

I see that there is a little misunderstanding about what I am asking about. In short I am asking if either:

  • There is already some implementation of it (at the compiler level I mean), but since hardly anybody uses it, almost nobody knows about it.
  • There is no mention of it in standard and no compiler vendor has though of it, but In principle it is possible to implement (once again: by the compiler, not compiled code.)
  • There is some deep-reaching problem with such an operation, that I missed.

My question was - which of those is true? And in case of the last - what is underlying problem?

I am not asking for workarounds.

j_kubik
  • 6,062
  • 1
  • 23
  • 42

2 Answers2

0

AFAIK C++ does not provide full reflection, which you would need to do that.

One solution is to provide reflection yourself (the way you describe is one way, it may not be the best one but it would work).

A totally non portable solution would be to locate the executable and use any debug information it may contain. Obviously non portable and requires the debug information to be there to begin with.

There's a decent description of the problem of reflection and different possible approaches to it in the introduction section of http://www.garret.ru/cppreflection/docs/reflect.html

Edit:

As I wrote above, there's no portable and general solution. But there may be a very non portable approach. I'm not giving you an implementation here as I do not have a C++ compiler at the moment to test it, but I'll describe the idea.

The basis is what Dave did in his answer: exploit the fact that a pointer to member is often just an offset. The problem is with base classes (especially virtual and multiple inheritance ones). You can approach it with templates. You can use dynamic casting to get a pointer to the base class. And eventually diff that pointer with the original to find out the offset of the base.

Analog File
  • 5,280
  • 20
  • 23
  • The description of reflection problems is quite nice, but proposed solutions (except getting programmer to do it himself) would be rather an overkill in my case. Since I am using gcc anyway, I could probably add some patch to it, but it's unlikely that it will become commonly used. Since I want to publish my sources, I cannot use such patches then. – j_kubik Sep 17 '12 at 21:13
  • Well, as I say, you need full reflection and full reflection is not part of the language (the language only provides limited reflection, see http://stackoverflow.com/questions/41453/how-can-i-add-reflection-to-a-c-application for a take on that). As that analysis says there are not many solutions. Either the user provides the metadata or you basically need to work at the language level (parser, preprocessor, compiler etc). The LLVM preprocessor could help, but it still is going to be complicated. Overkill as you say, may be the only kill. – Analog File Sep 17 '12 at 21:26
  • I added an idea to the answer. It may or may not be possible. I have no compiler at hand here, so it's just an idea for you to explore, not a real complete answer. And surely it would not be portable. – Analog File Sep 17 '12 at 21:38
  • It wouldn't solve problem with virtual base classes, as in this case member-pointer cannot be simple offset. Also see my edit. – j_kubik Sep 21 '12 at 23:18
0

There is no cross platform way to do this. Pointer to member values are commonly implemented as offsets to the start of the object. Leveraging off of that fact I made this (works in VS, haven't tried anything else):

class A
{
public:
    int i, j;
};

int main()
{
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;

    union
    {
        std::ptrdiff_t offset;
        int A::*s;
    };

    offset = r - reinterpret_cast<int*>(&a);
    a.*s = 7;
    std::cout << a.i << '\n';
}
David
  • 27,652
  • 18
  • 89
  • 138
  • And how about virtual base classes? – j_kubik Sep 17 '12 at 21:02
  • You can't; the only one who can is compiler vendor - my question was rather: is there some typical (but rather unknown) way compiler vendors would implement it, or is it simply impossible? – j_kubik Sep 17 '12 at 21:15