pointer to member conversion to a pointer to member that is a member's base class

V

Vladimir_petter

Dear All,

There is the problem in nutshells (see the program bellow):

It is ok to convert pointer to F<T> to the pointer to I.
Now if I have pointer to member "F<T> entity::*" can I convert it to the "I
entity::*"?
Compiler does not let me to do that (I've tried on VC 7.1 and Comeau 4.3.3).
If I do reinterpret_cast then the program will be compiled and runs as
expected all though I would like to know possible implications of this
approach.

The goal here to create a static array of fields for a class and be able to
execute algorithms on this array (like the for loop in the main function).

Thanks,
Vladimir.

#include <string>

using namespace std;

struct I
{
virtual char const * foo()=0;
};

template <typename T>
struct F : public I
{
char const * foo()
{
return typeid(T).name();
}

T v_;
};

struct entity
{
typedef I entity::* mem_t;

static mem_t fields[4];

F<int> f1_;
F<char> f2_;
F<string> f3_;
F<double> f4_;
};

entity::mem_t entity::fields[4] = {
reinterpret_cast<mem_t>(&entity::f1_),
reinterpret_cast<mem_t>(&entity::f2_),
reinterpret_cast<mem_t>(&entity::f3_),
reinterpret_cast<mem_t>(&entity::f4_),
};


int main(int, char **)
{
entity e;
for(int i=0; i<4; ++i)
{
printf("%s\n", (e.*(entity::fields)).foo());
}

return 0;
}
 
V

Victor Bazarov

Vladimir_petter said:
There is the problem in nutshells (see the program bellow):

It is ok to convert pointer to F<T> to the pointer to I.

Yes said:
Now if I have pointer to member "F<T> entity::*" can I convert it to the "I
entity::*"?

Not implicitly, no.
Compiler does not let me to do that (I've tried on VC 7.1 and Comeau 4.3.3).

That's right. In the current Standard no such conversion exist.
If I do reinterpret_cast then the program will be compiled and runs as
expected all though I would like to know possible implications of this
approach.

As the language is defined now, your program causes undefined behaviour.
It might even work as expected (and apparently it does). But it might not
or it might do something really bad, like format your hard drive.

If I were you, I'd present my case to comp.std.c++ and asked for the
addition to the language: a pointer to a member of T of type D should be
convertible to a pointer to a member of T of type B if B is an unambiguous
and accessible base of D. It is a logical extension to 4.10/3.

In C++ terms: {D cv T::*} should be convertible to {B cv T::*} and
{D cv T::&} should be convertible to {B cv T::&} (which
is implied because all pointer conversions are applicable to references
with the exception that there are no null references)
The goal here to create a static array of fields for a class and be able to
execute algorithms on this array (like the for loop in the main function).

Sounds good.
Thanks,
Vladimir.

#include <string>

using namespace std;

struct I
{
virtual char const * foo()=0;
};

template <typename T>
struct F : public I
{
char const * foo()
{
return typeid(T).name();
}

T v_;
};

struct entity
{
typedef I entity::* mem_t;

static mem_t fields[4];

F<int> f1_;
F<char> f2_;
F<string> f3_;
F<double> f4_;
};

entity::mem_t entity::fields[4] = {
reinterpret_cast<mem_t>(&entity::f1_),
reinterpret_cast<mem_t>(&entity::f2_),
reinterpret_cast<mem_t>(&entity::f3_),
reinterpret_cast<mem_t>(&entity::f4_),
};


int main(int, char **)
{
entity e;
for(int i=0; i<4; ++i)
{
printf("%s\n", (e.*(entity::fields)).foo());
}

return 0;
}


Victor
 
V

Vladimir_petter

Hello Viktor,

I apriciate your response.
That's right. In the current Standard no such conversion exist.

Could you point me to a paragraph in the standard that would clearly state
this?
I was looking in the 4.11, 5.2.9/9, 5.3.1/2, 8.3/3. None of them clearly
states that
this is invalid.
As the language is defined now, your program causes undefined behaviour.
It might even work as expected (and apparently it does). But it might not
or it might do something really bad, like format your hard drive.

If I were you, I'd present my case to comp.std.c++ and asked for the
addition to the language: a pointer to a member of T of type D should be
convertible to a pointer to a member of T of type B if B is an unambiguous
and accessible base of D. It is a logical extension to 4.10/3.

Well I think I'll do that. Unfortunately it would not help to solve my
current problem :-(.
In C++ terms: {D cv T::*} should be convertible to {B cv T::*} and
{D cv T::&} should be convertible to {B cv T::&} (which
is implied because all pointer conversions are applicable to references
with the exception that there are no null references)

I agree with everithing you said above except that I think there is no such
a think as
a reference to a member (see 8.3.2/3).
Sounds good.

But yet unreachable :-(.

Thanks,
Vladimir.
 
V

Victor Bazarov

Vladimir_petter said:
Hello Viktor,

I apriciate your response.


Could you point me to a paragraph in the standard that would clearly state
this?

How can I point you to the paragraph that doesn't exist? See the entire
Clause 4, if you can't find it, it doesn't exist. Clause 4 contains _all_
conversions there are.
I was looking in the 4.11, 5.2.9/9, 5.3.1/2, 8.3/3. None of them clearly
states that
this is invalid.

The Standard is organized in a peculiar way. If certain things are not
explicitly allowed, they are prohibited. That includes conversions. If
there is no operation that is explicitly allowed in 5.2.10, it is not
allowed even with a reinterpret_cast.
Well I think I'll do that. Unfortunately it would not help to solve my
current problem :-(.

No, but it probably will ensure that when time comes to port it elsewhere
you will have a working solution. Meanwhile enjoy your reinterpret_cast
solution while it "works".
I agree with everithing you said above except that I think there is no such
a think as
a reference to a member (see 8.3.2/3).

Well, OK, but perhaps there should be. :)
But yet unreachable :-(.

I am not sure I understand. Didn't you indicate in your original post
that your code works as you want it?

V
 
A

Alexander Grigoriev

Use static_cast. It allows for those explicit convertions, if the original
and target types are compatible.
 
V

Vladimir_petter

Hello Viktor,
How can I point you to the paragraph that doesn't exist? See the entire
Clause 4, if you can't find it, it doesn't exist. Clause 4 contains _all_
conversions there are.


The Standard is organized in a peculiar way. If certain things are not
explicitly allowed, they are prohibited. That includes conversions. If
there is no operation that is explicitly allowed in 5.2.10, it is not
allowed even with a reinterpret_cast.

Now I see. Thanks.
No, but it probably will ensure that when time comes to port it elsewhere
you will have a working solution. Meanwhile enjoy your reinterpret_cast
solution while it "works".


Well, OK, but perhaps there should be. :)


I am not sure I understand. Didn't you indicate in your original post
that your code works as you want it?

What I've meant was that compiler does not guarantee that this mechanism
will work. So I can do that only on my own risk and in that case I should
clearly understand in which cases it will work and in which cases it would
not. Now after making some experiments and reading this article:
http://www.codeproject.com/cpp/FastDelegate.asp#xx876855xx
I think that reinterpret_cast solution will work only if "I" (see program in
the first post) is not virtually inherited the very base class (first in
hierarchy) of "F<T>", which is true in my case. But for safety I will
provide a way to verify this during compilation and issue an error if this
invariant is broken.

Thanks,
Vladimir
 
A

Alexander Grigoriev

Victor Bazarov said:
Are they compatible? How do you define "compatible"?

If there exists static_cast from B* to D * and vice versa (B being base
class of D), then there exist both implicit conversion from pointer to
member of base B to pointer to member of derived D (4.11/2) and explicit
static_cast to another direction (5.2.9/9).
 
V

Victor Bazarov

Alexander said:
If there exists static_cast from B* to D * and vice versa (B being base
class of D), then there exist both implicit conversion from pointer to
member of base B to pointer to member of derived D (4.11/2) and explicit
static_cast to another direction (5.2.9/9).

Did you miss the fact that it's not a member of B or member of D the OP
was asking about? They both are members of 'T', but one is of class B
and the other is of class D. B T::* and D T::*. Can we simply drop the
fact that they are pointers to members of the same type? I submit that
we cannot.

Victor
 
A

Alexander Grigoriev

Victor Bazarov said:
Did you miss the fact that it's not a member of B or member of D the OP
was asking about? They both are members of 'T', but one is of class B
and the other is of class D. B T::* and D T::*. Can we simply drop the
fact that they are pointers to members of the same type? I submit that
we cannot.

Victor

Yes, such conversion doesn't seem possible, other than brute-force
reinterpret_cast.
 
V

Victor Bazarov

Alexander said:
Yes, such conversion doesn't seem possible, other than brute-force
reinterpret_cast.

reinterpret_cast is not the "catch all" method. It still must behave
according to the language rules. The Standard specifies a strict set of
conversions _permitted_ to be done using reinterpret_cast (see 5.2.10)
and this one isn't one of them either. So, "brute force" will result in
_undefined_behaviour_.

I think the language could be changed to permit that conversion (even to
let it be implicit), but it's a issue to be resolved in comp.std.c++.

Victor
 
V

Victor Bazarov

Vladimir_petter said:
Dear All,

There is the problem in nutshells (see the program bellow):
[..]

I posted your message along with my summary to comp.std.c++. If and
when there are replies, I'll report back here.

Victor
 
V

Vladimir_petter

Hello Viktor,
There is the problem in nutshells (see the program bellow):
[..]

I posted your message along with my summary to comp.std.c++. If and
when there are replies, I'll report back here.

Thanks for your efforts. I actually posted my question to the
comp.lang.c++.moderated, but might be I've picked up a wrong group or the
way I put the problem is not right, but so far there was no response.
Anyways I've marked your posting in comp.std.c++ and will monitor it.

Thanks,
Vladimir.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top