Copying the data is more expensive than type punning. In my opinion, the simplest way to prevent this from being a problem is to prevent pointers or references being taken to members of such a union (perhaps you would need to declare it as a new kind of union, to avoid legacy code breakage). In C this would be untenable, but I think that in C++ it will not be such a problem, as you could easily create a union_iterator that could be an iterator of float, now that rvalue results from operator*() are permitted. This would be greatly simplified if the language had better support for proxy objects, such as the various proposals for overriding auto. This should interact just fine with static aliasing, as aliases to the union contents are never created and thus strict aliasing is preserved.
For example, consider this hypothetical sample, where I have trimmed some of the boilerplate and named the hypothetical new kind of union "union class", for no actual reason.
union class pun {
float f;
int i;
};
template<typename pun_iterator> class pun_float_iterator : iterator_facade<pun_float_iterator<pun_iterator>> {
pun_iterator it;
pun_float_iterator(pun_iterator x) : it(x) {}
pun_float_iterator(const pun_float_iterator& other) : it(
other.it) {}
struct proxy {
proxy(pun_iterator x) : it(x) {}
proxy(const proxy& other) : it(
other.it) {}
pun_iterator it;
operator float() { return it->f; }
proxy& operator=(const float& f) { it->f = f; return *this; }
};
proxy operator*() { return proxy(it); }
};
std::vector<pun> x;
// fill x
std::vector<float> f(make_float_pun_iterator(x.begin()), make_float_pun_iterator(x.end()));
With compile-time reflection, one could write a generic punning iterator that would pun a given member from any such union, which would definitely be smoother, but not required, or even a functional iterator, especially with polymorphic lambdas.
As far as type requirements go, I think that POD is a little too far. What we would really be talking about is that all types must be trivially constructible, and trivially destructible, and union class is both. If all are trivially movable, then union class is trivially movable. If all are trivially copyable, then union class is trivially copyable.
The main problem is trap representations. It's difficult for me to argue that this would result in safe, portable code, if in fact punning objects may result in trap representations killing the program. I mean, there's a difference between punning a pointer, which would be explicitly quite unsafe, and punning an integer and a float. On that note, it may be undesirable to introduce a Standardised type pun for objects like float where there's no Standardised way to determine their representation, as you'd just have to fall back to implementation details to make it work anyway. For example, the fast inverse square root code which employs type punning could not be made portable just because the type pun would be portable.