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?
@riley what do you mean by a conversion between pointer types?
-
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?
@riley
```
struct foo f;
struct bar b;
void *p = (void *) &f;
b = *((struct bar *) p);
```
whatever happens the previous have to pass, C rules -
@riley what do you mean by a conversion between pointer types?
@oblomov Defining a function/operator that would be implicitly invoked when
struct foo *is passed to a function declared to accept astruct bar *that would ideally amount to adding a small constant to the pointer; effectively, there's astruct barinside astruct foo, and I'd like astruct bar *to be converted tostruct foo *by implicitly referring to that inner struct when a pointer to the outer struct is being passed to a function taking a pointer to the inner struct. -
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?
@riley Tricky question. In both C and C++, punning between pointers to unrelated types is undefined behaviour. It may "work" when you test it, but the compiler optimiser may also break it at any point. E.g.
```cpp
// It doesn't matter that foo and bar are layout-compatible
struct foo { int x; };
struct bar { int x; };struct foo a = {42};
struct foo* a_ptr = &a;struct B* b_ptr = a_ptr;
std::cout << b_prt->x; // undefined behaviour
``` -
@oblomov Defining a function/operator that would be implicitly invoked when
struct foo *is passed to a function declared to accept astruct bar *that would ideally amount to adding a small constant to the pointer; effectively, there's astruct barinside astruct foo, and I'd like astruct bar *to be converted tostruct foo *by implicitly referring to that inner struct when a pointer to the outer struct is being passed to a function taking a pointer to the inner struct. -
@riley Tricky question. In both C and C++, punning between pointers to unrelated types is undefined behaviour. It may "work" when you test it, but the compiler optimiser may also break it at any point. E.g.
```cpp
// It doesn't matter that foo and bar are layout-compatible
struct foo { int x; };
struct bar { int x; };struct foo a = {42};
struct foo* a_ptr = &a;struct B* b_ptr = a_ptr;
std::cout << b_prt->x; // undefined behaviour
```@lesley I don't actually want punning; I want to avoid having to declare an extra procedure that would take
struct foo *if I've already written one that takesstruct bar *. I've got a bunch of these procedures, and while I could autogenerate the extra procedures asinlineprocedures, I'd rather not do it if I can have the translator do the work for me, and keep the code less bulky and more readable. -
@lesley I don't actually want punning; I want to avoid having to declare an extra procedure that would take
struct foo *if I've already written one that takesstruct bar *. I've got a bunch of these procedures, and while I could autogenerate the extra procedures asinlineprocedures, I'd rather not do it if I can have the translator do the work for me, and keep the code less bulky and more readable.@riley Ahh. Then I don't think I have an answer
-
@lesley yes, but in the case of @riley that's not the same issue: if foo has-a bar, there's no way to do the casting _implicitly_, as far as a I know. It would be possible with references by defining an implicit constructor of bar from foo, but this won't be applied to pointers.
The only work around I can think of is to define an overloaded function
bar * get_bar(bar * o) { return o; }
bar * get_bar(foo * o) { return &o->bar_element; }and wrap pointer arguments with that function.
-
-
-
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.