I just came across this question and the two previous answers. While the chosen answer is beautifully succinct, correct, and specific to the particulars of the question (the given class is a POD), I wanted to clarify something for folks arriving here looking for information about "C++ Casting back from member pointer to holding class pointer" as the title suggests.
Briefly, the C++11 standard split the technical definition of a POD into two separate concepts: a trivial class and a standard-layout class. Since C++11 became a standard, calling a type "POD" (or more formally a "POD struct") implies it is both trivial and standard-layout.
However, for the purposes of casting a pointer-to-object to/from a pointer-to-first-member, the important thing is that the object's type is a standard-layout class. Particularly, it doesn't matter whether or not the object's type is also a trivial class.
This means, for example, that the SSVec class in the original question could have user-defined (non-trivial): default constructors, copy/move constructors/assignment operators, and/or destructor.
I believe it is important to note this, as it means this kind of cast, as well as some other interesting casts, are defined behavior for many more types of classes than if it were restricted to a POD. The C++11 concept of standard-layout was originally sometimes informally referred to as a "relaxed" POD for this very reason.
So, the first part of the example code from the chosen answer could safely be changed to:
SSVec* SSVec_cast(float* ptr) {
// Break if someone changes SSVec to be a non-standard-layout class:
static_assert(std::is_standard_layout<SSVec>::value, "SSVec is no longer a standard-layout class!");
...
Notes:
The C++14 standard did not change the definition of POD struct, standard-layout class, or trivial class.
I haven't checked the C++17 standard, but I haven't read anywhere that it changed these definitions significantly either.
It cannot be stressed enough that when writing code that depends on a class being standard-layout, a static_assert
is always used as the chosen answer shows; just use std::is_standard_layout
instead of std::is_pod
in the test.
Under C++17 you can use std::is_standard_layout_v<SSVec>
instead of std::is_standard_layout<SSVec>::value
.
See Also
C++ standard type traits at cppreference:
std::is_pod: both trivial and standard-layout.
std::is_standard_layout: a scalar type, a standard-layout class, or an array of such type/class, possibly cv-qualified
std::is_trivial: a scalar type, a trivially copyable class with a trivial default constructor, or array of such type/class, possibly cv-qualified.
Pseudo-concepts at cppreference:
For advanced information, these stackoverflow articles: