Consider the following program:
#include <algorithm>
#include <iostream>
#include <vector>
struct foo {
foo(int value)
: value_(value)
{
// perform range checks
}
int value() const {
return value_;
}
private:
int value_;
};
int main() {
std::vector<foo> values{0, 1, 2, 3, 4, 5};
std::for_each(std::begin(values), std::end(values),
[](foo& f){ std::cout << f.value(); });
std::cout << std::endl;
std::for_each(reinterpret_cast<const int*>(values.data()),
reinterpret_cast<const int*>(values.data()) + values.size(),
[](int i){ std::cout << i; });
}
After compiling it with Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn), it produces the following output (which is exactly what I want):
012345
012345
The first iteration is trivial. The second iteration however is performed not through iterators, but through pointers to the underlying storage which have been cast to const int*
.
My question is: Is that code legal?
My intuition is that it is. According to §5.2.10/7 of the C++11 standard (final working draft):
When a prvalue v of type “pointer to
T1
” is converted to the type “pointer to cvT2
”, the result isstatic_cast<cvT2*>(static_cast<cvvoid*>(v))
if bothT1
andT2
are standard-layout types (3.9) and the alignment requirements ofT2
are no stricter than those ofT1
If I interpret this correctly, then the code above should be correct, right? If not, can it be made to work?
(In my answer I use C++14 standard draft (N4140), which is a bit different from C++11 with regard to relevant quotes)
reinterpret_cast<const int*>(values.data())
is fine because of[class.mem]/19
:And regarding dereferencing,
[expr.reinterpret.cast]/7
:First
static_cast
is covered by[conv.ptr]/2
:Second
static_cast
-[expr.static.cast]/13
:Alignment requirement is satisfied because of
[class.mem]/19
, so the cast works fine.But the problem is that there seem to be no guarantee that
sizeof(foo) == sizeof(int)
except aforementioned requirement forstd::complex
. One can interpret the note about unnamed padding from[class.mem]/19
as allowing padding only if it's needed for alignment, so there must not be any padding in your case, but in my opinion that note is too vague in this regard.What you can do is put in your code
So at least your code won't compile if the requirements are violated.