You missed part of the room. The above class definition is perfectly valid if you also define Account::period somewhere (but without providing an initializer). See last post 9.4.2 / 3:
An element still needs to be defined in the namespace area if it is used as odr (3.2) in the program, and the namespace area definition should not contain an initializer.
All of this discussion applies only to constexpr static data elements, and not to namespace-scope static variables. When the static data members are constexpr (and not just const), you must initialize them in the class definition. So your question should really be: What can you do with a constexpr static data element so that you don’t have to give a definition for it in the namespace area?
From the previous one, the answer is that the member should not be used as odr. And you have already found the relevant parts of the odr-used definition. Thus, you can use an element in a context where it is not potentially evaluated, like an invaluable operand (e.g. sizeof or decltype ) or its subexpression. And you can use it in an expression that immediately applies the lvalue-to-rvalue transform.
So now we get to . What use of a variable causes an immediate conversion of lvalue to rvalue?
Part of this answer is given in §5 / 8:
Whenever a glvalue expression appears as the operand of an operator that expects a prvalue for that operand, lvalue-to-rvalue (4.1), the array-to-pointer standard (4.2), or the standard conversion pointer function (4.3) are used to transform the expression in prvalue.
For arithmetic types, which are mainly applied to all operators that apply standard arithmetic conversions. Thus, you can use the element in various arithmetic and logical operations without requiring a definition.
I cannot list all the things that you can or cannot do here, because the requirements that something is [g] lvalue or [p] rvalue are spread by standard. Rule of thumb: if only the value for the variable is used, the conversion of lvalue to rvalue is applied; if a variable is used as an object , it is used as an lvalue.
You cannot use it in contexts where the lvalue value is explicitly required, for example, as an argument to an address operator or mutating operators). Direct linking of lvalue links (without conversion) is such a context.
A few more examples (without detailed standard analysis):
You can pass it to functions if the function parameter is not a reference to which you can directly bind a variable.
To return from a function: if the implicit conversion to the type of the returned object includes a user-defined conversion function, the rules apply to go to the function. Otherwise, you can return it if the function does not return an lvalue (reference) value that refers directly to the variable.
The key rule for variables using odr, the "One Definition Rule" is in 3.2 / 3:
Each program must contain exactly one definition of each non-line function or variable that is used in this program odr; No diagnostic required.
The component “without the need for diagnostics” means that programs that violate this rule cause undefined behavior, which can vary from failure to compile, compile and crash in amazing compilation methods and actions, as if everything is in order. And your compiler should not warn you about the problem.
The reason, as others have already pointed out, is that many of these violations will only be detected by the linker. But optimization may have removed object references, so there is no reason for the connection to fail, otherwise the connection can sometimes occur only at run time or be determined to select an arbitrary instance from several name definitions.