All type punning is in the hands of the implementation. The language definition provides the syntax for it, which has the virtuel that all code which attempts to do type punning expresses it in the same manner. However, the language leaves it up to implementations to define whether type punning works, and with what caveats and restrictions.
There is some hand-waving in the definition of memcpy so that copying compatible objects is well-defined.
Yes, you can. The behavior is implementation-defined but not undefined. (Well, it can trigger undefined behavior if the value corresponds to a signaling NaN, or if the implementation uses a nonstandard, non-IEEE format for doubles that has other "trap representations". But it's not otherwise undefined.)
The basis for this is that the aliasing rule has an explicit exception for reading or writing to objects using char pointers, i.e. byte-by-byte, regardless of the object's type. This exception is in both the C standard:
https://port70.net/~nsz/c/c11/n1570.html#6.5p7
and the C++ standard:
http://eel.is/c++draft/expr.prop#basic.lval-11.8
The memcpy function is defined as copying characters, so the exception applies to it too.
Both standards also explicitly define that objects (at least of POD types) have byte representations and those representations are implementation-defined (as opposed to triggering undefined behavior if you depend on them). For C:
> Except for bit-fields, objects are composed of contiguous sequences of one or more bytes, the number, order, and encoding of which are either explicitly specified or implementation-defined.
https://port70.net/~nsz/c/c11/n1570.html#6.2.6.1
C++:
If you memcpy a uint64_t to a double, the implementation is not required to notice that the double variable's value has changed; a subsequent access to that variable can continue to refer to a register. It's not a matter of what bit pattern was stored there.
> 3.1 > 1 access >〈execution-time action〉 to read or modify the value of an object
Thus, the requirement is symmetrical. The compiler must consider any char write as potentially aliasing a subsequent read (or write) of any type, unless it can prove non-aliasing without depending on type. And similarly, it must consider a write of any type as potentially aliasing a subsequent char read/write.