Dr. Gut
Dr. Gut

Reputation: 2836

Is it safe to reinterpret_cast between a Type and a Wrapper<Type>?

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

Answers (1)

HolyBlackCat
HolyBlackCat

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)

[basic.compound]/4.3

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

Related Questions