Reputation: 2836
Suppose we have class template Wrapper
like this:
template <class T>
struct Wrapper { T wrapped; };
For what types is it safe to reinterpret_cast
between a Type
and a Wrapper<Type>
? None? Standard-layout? All?
Suppose we created an object of one of these (Type
and Wrapper<Type>
), and read and write this object through the other. Example (live on godbolt.org):
void F1() {
std::stringstream ss;
ss << "Hello";
reinterpret_cast<Wrapper<std::stringstream>&>(ss).wrapped << " world";
}
void F2() {
Wrapper<std::stringstream> ss;
ss.wrapped << "Hello";
reinterpret_cast<std::stringstream&>(ss) << " world";
}
Reading the comments of this answer this area seems to be not quite unequivocal in the standard. I think that all compilers would generate a code that works as expected (i.e. a value of one type can be cast to the other), but the standard may not currently guarantee this. If it doesn't, the question arises: Could the standard guarantee well defined behaviour with these casts, or is it not possible/impractical to guarantee anything in such a case?
Cause I am pretty sure, that these casts will actually work.
Upvotes: 4
Views: 398
Reputation: 96286
Reinterpreting T
(that's not a member of Wrapper<T>
) as Wrapper<T>
is never allowed (the F1
example).
On the other hand, I believe reinterpreting Wrapper<T>
as T
is allowed for standard-layout classes: (the F2
example)
Two objects a and b are pointer-interconvertible if:
— one is a standard-layout class object and the other is the first non-static data member of that object, or ...
And right below that:
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a
reinterpret_cast
. ...
Note that while this rule is symmetrical, it requires both objects to actually exist. If you have a reference to T
pointing to the member of Wrapper<T>
, then you can reinterpret it as Wrapper<T>
(and the other way around). But if it points to a T
object that's not a member of Wrapper<T>
, then it would be UB.
Disclaimer: By "such-and-such reinterpreting is not allowed" I mean that accessing the result of the reinterpret_cast
would cause UB. The cast itself shouldn't cause UB.
Upvotes: 6