Hello #cpp / #cplusplus Fediverse,
-
-
Hello #cpp / #cplusplus Fediverse,
If I've got types
struct fooandstruct bar, which are unrelated by formal class inheritance, is there some way to define a conversion fromstruct foo *tostruct bar *?)I can't attach a plain old conversion operator to a pointer type, even if I name it, and none of the C++ compilers that I tried thinks of invoking a reference conversion operator when what's supposed to be implicitly converted, and the expectant receptacle, are nominally pointers.
Is there a way?
A pointer conversion is not a reference conversion, you can't do what you want without relying on undefined behaviour in the first place (well, at least, not in current C++). The best you can do is `reinterpret_cast` or `std::bit_cast` the pointer, but there's a reason ripcast is a code smell.
Telling that your pointer to one type is a pointer to other type is not very kosher, you are trying to build a pretty hefty footgun there. I hope you know what you are doing.
-
@riley Ahh. Then I don't think I have an answer
@lesley If
foovirtually inherited fromstruct bar, it might possibly work, butfoowould then have to beclassrather thanstruct, and begin with the vtable pointer, which C++ doesn't let me make static or place it somewhere away from the class's beginning where it implicitly goes. -
A pointer conversion is not a reference conversion, you can't do what you want without relying on undefined behaviour in the first place (well, at least, not in current C++). The best you can do is `reinterpret_cast` or `std::bit_cast` the pointer, but there's a reason ripcast is a code smell.
Telling that your pointer to one type is a pointer to other type is not very kosher, you are trying to build a pretty hefty footgun there. I hope you know what you are doing.
@riley Though I guess you could overload the function where you are trying to pass the pointer into, and do the conversion there, but I'd imagine most sane code reviewers would stop that.
```cpp
int func(bar* bar) {
// do the bar stuff
}int func(foo* foo) {
return func(reinterpret_cast<bar*>(foo));
}
```For educational purposes only, please don't do this in code that somebody else has to touch.
-
-
A pointer conversion is not a reference conversion, you can't do what you want without relying on undefined behaviour in the first place (well, at least, not in current C++). The best you can do is `reinterpret_cast` or `std::bit_cast` the pointer, but there's a reason ripcast is a code smell.
Telling that your pointer to one type is a pointer to other type is not very kosher, you are trying to build a pretty hefty footgun there. I hope you know what you are doing.
@ananas You're thinking about something weird.
I want to do something like this, which, as you can see, is so perfectly cromulent than it compiles and runs:
#include <stdio.h>
#include <stdlib.h>
struct bar {
int paydirt;
};
struct foo {
int some_field_here;
struct bar cheap_dirt;
operator bar &() {
return cheap_dirt;
}
};
void work_on_paydirt (struct bar &object) {
printf("Teh paydirt is %i\n", object.paydirt);
}
struct foo the_foo;
struct bar the_bar;
int main () {
work_on_paydirt(the_foo);
work_on_paydirt(the_bar);
return EXIT_SUCCESS;
}I just want
work_on_paydirt, for historic compatibility reasons, to takestruct bar *rather thanstruct bar &as its argument. Logic-wise, maintenance-wise, there's no difference. Even the generated code is exactly the same (modulo the mangled names). But C++ syntax is only happy to let me define an explicit conversion operator for a struct-to-struct-reference, and not for the same struct's pointer to a struct pointer. I'm not trying to do anything exotic here, or type punning or obfuscatory stuff; I just want the translator to implicitly invoke my type converter for a pointer-to-struct type, just like it can for a referenced-struct type. -
@oblomov Having
foobe aclassand not astructwould make some things a lot more complicated. If there's no other way, I'd probably prefer to generate automatically the procedures that takestruct bar *, invoke the converter explicitly, and then call the hand-written procedures, over doing multiple inheritance. -
@oblomov Having
foobe aclassand not astructwould make some things a lot more complicated. If there's no other way, I'd probably prefer to generate automatically the procedures that takestruct bar *, invoke the converter explicitly, and then call the hand-written procedures, over doing multiple inheritance. -
@riley Though I guess you could overload the function where you are trying to pass the pointer into, and do the conversion there, but I'd imagine most sane code reviewers would stop that.
```cpp
int func(bar* bar) {
// do the bar stuff
}int func(foo* foo) {
return func(reinterpret_cast<bar*>(foo));
}
```For educational purposes only, please don't do this in code that somebody else has to touch.
@ananas That's my fall-back approach, except it's not
reinterpret_cast<bar*>(foo), it'sfoo->gimme_bar(). Andfoo::gimme_bar()will beinline, and so will be the couple hundred procedures that takestruct foo *, so in the end, very little binary code will come out of it, only the source code will be awfully bulky. Not ideal. -
-
@oblomov Never mind:
#include <stdio.h>
struct par1 {
int par1a;
par1() : par1a(1) {}
};
struct par2 {
int par2a;
par2() : par2a(2) {}
};
struct child : par1, par2 {
int chfield3;
child() : chfield3(3) {}
};
int main () {
child ch;
printf("ch.par1a = %i, ch.par2a = %i, ch.chfield3 = %i\n",
ch.par1a, ch.par2a, ch.chfield3);
printf("&ch = %p, (par1 *)&ch = %p, (par2 *)&ch = %p\n",
&ch, (par1 *)&ch, (par2 *)&ch);
return 0;
}I might be able to make this work. Pondering.
-
sure: https://godbolt.org/z/YvYa9b7jb
You do lose the POD property on foo though. Depending on your needs this may or may not be important.
-
@ananas That's my fall-back approach, except it's not
reinterpret_cast<bar*>(foo), it'sfoo->gimme_bar(). Andfoo::gimme_bar()will beinline, and so will be the couple hundred procedures that takestruct foo *, so in the end, very little binary code will come out of it, only the source code will be awfully bulky. Not ideal.@ananas Well, if I have to autogenerate, I could do this instead:
template <class T>
void work_on_paydirt (T *ambi_object) {
struct bar *object = ambi_object->gimme_bar();
printf("Teh paydirt is %i\n", object->paydirt);
}Slightly less bulky, but it looks ugly.
-
sure: https://godbolt.org/z/YvYa9b7jb
You do lose the POD property on foo though. Depending on your needs this may or may not be important.
-