(Self-answered as I think I found the complete answer during the progress of posting the question)
[cstring.syn] Covers that we need to turn to the C standard library header string.h for the meaning of std::memset:
namespace std {
// ...
void* memset(void* s, int c, size_t n);
// ...
}
/1 The contents and meaning of the header are the same as
the C standard library header <string.h>. [...]
E.g. the C11 draft via N1570 specifies that the C standard library memset copies a byte (unsigned char) into the first n bytes of the destination object [emphasis mine]:
7.24.6.1 The memset function
/1 Synopsis
#include <string.h>
void *memset(void *s, int c, size_t n);
/2 Description
The memset function copies the value of c (converted to an unsigned
char) into each of the first n characters of the object pointed to by
s.
/3 Returns
The memset function returns the value of s.
Since this is the C standard "object" does not mean the same things as in C++; Section 3.15p1:
object region of data storage in the execution environment, the contents of which can represent values
With this in mind, we go back to the C++ standard and [basic.types]/4, which tells us that the object representation of a (C++) object is the sequence of underlying unsigned char objects, and that for trivially copyable types, particularly, the value representation of the object is part of the object representation:
The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). [...] For trivially copyable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values42.
with the footnote 42 clarifying the intent of this memory model representation allowing compatibility when interfacing with the C:
The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C.
[basic.types]/3 expands on the effect of byte-wise copy of the underlying bytes from a source object to destination object (both of trivially copyable type), with an additional restriction that neither the source nor the destination object of such a byte-copy operation shall be a potentially-overlapping subobject:
For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a potentially-overlapping subobject, if the underlying bytes ([intro.memory]) making up obj1 are copied into obj2,41 obj2 shall subsequently hold the same value as obj1.
From this this is holds that std::memset may be used to set all (n == sizeof(T)) or a sub-set of (n < sizeof(T)) of the unsigned char objects in the underlying object representation of an object whose type is trivially copyable and where the object is not a potentially-overlapping subobject. The resulting value representation of the object is a discrete element of an implementation-defined set of values that the particular object represents. Note however that reading these values is not necessarily well-defined, one notorious example being using std::memset to set all the bits of a floating point to zero in a non-IEEE754-adhering implementation where "all bits zero" could represent a trap. Another thing to consider when using std::memset is that whilst it may create formally well-defined objects (in the standardese sense) their resulting values may violate class invariants.