I have looked at the following — related — questions, and none of them seem to address my exact issue: one, two, three.
I am writing a collection of which the elements (key-value pairs) are stored along with some bookkeeping information:
struct Element {
Key key;
Value value;
int flags;
};
std::vector<Element> elements;
(For simplicity, suppose that both Key
and Value
are standard-layout types. The collection won't be used with any other types anyway.)
In order to support iterator-based access, I've written iterators that override operator->
and operator*
to return to the user a pointer and a reference, respectively, to the key-value pair. However, due to the nature of the collection, the user is never allowed to change the returned key. For this reason, I've declared a KeyValuePair
structure:
struct KeyValuePair {
const Key key;
Value value;
};
And I've implemented operator->
on the iterator like this:
struct iterator {
size_t index;
KeyValuePair *operator->() {
return reinterpret_cast<KeyValuePair *>(&elements[index]);
}
};
My question is: is this use of reinterpret_cast
well-defined, or does it invoke undefined behavior? I have tried to interpret relevant parts of the standard and examined answers to questions about similar issues, however, I failed to draw a definitive conclusion from them, because…:
- the two struct types share some initial data members (namely,
key
andvalue
) that only differ inconst
-qualification; - the standard does not explicitly say that
T
andcv T
are layout-compatible, but it doesn't state the converse either; furthermore, it mandates that they should have the same representation and alignment requirements; - Two standard-layout class types share a common initial sequence if the first however many members have layout-compatible types;
- for union types containing members of class type that share a common initial sequence, it is permitted to examine the members of such initial sequence using either of the union members (9.2p18).
– there's no similar explicit guarantee made about
reinterpret_cast
ed pointers-to-structs sharing a common initial sequence. – it is, however, guaranteed that a pointer-to-struct points to its initial member (9.2p19).
Using merely this information, I found it impossible to deduce whether the Element
and KeyValuePair
structs share a common initial sequence, or have anything other in common that would justify my reinterpret_cast
.
As an aside, if you think using reinterpret_cast
for this purpose is inappropriate, and I'm really facing an XY problem and therefore I should simply do something else to achieve my goal, let me know.
reinterpret_cast
is almost always the wrong approach, shouldn't aconst_cast
work well for what you're claiming? – Hollomanconst_cast
should work in this case, but let me try it – it's still not clear, however, whetherconst_cast
compiling would mean that this is well-defined. – Bechtreinterpret_cast
can't guarantee anything. – Holloman