
Unless you mean to say that any program that uses a NaN in any way has undefined behavior, this notion of a "well-formed value" seems arbitrary and capricious.
The notion of "well-formed value" comes for Elements of Programming. NaN is given as an example of something that is not well-formed. It's defined in the first couple of pages, IIRC. Any state of an object that does represent a value (e.g., NaN does not represent a real number) is not a well-formed value. I can assure that neither Alex nor Paul would consider the definition to be arbitrary or capricious. A program that checks for NaN as the result of an invalid computation does not have undefined behavior because it is explicitly checking for that state. A program that uses NaN as if it were a real number should have undefined behavior. It is easy to construct examples of programs where NaN breaks the postconditions of STL algorithms: double s[] { NaN }; assert(find(s, s + 1, NaN) == s); // will fail double s[] { ..., NaN, ... }; sort(s, s + N); assert(is_sorted(s, s + N)); // probably fails Comparisons on NaN do not conform to the usual semantics of equality and ordering, and so the programs have undefined behavior. This is because the algorithms are generic and are only concerned with the comparison of values, not the checking of those computations for invalid results. There's nothing wrong with having a type or set of types with a representation that includes an ill-formed value. It can be very useful for checking error states. However, such states may not be included in the set of values represented by that type. Andrew