One definition rule tells us that we cannot have more than one odr-used definition in a program. Therefore, if a variable is used by odr, you need to define it, but you cannot define its header file, since it can be included more than once by the whole program. Violations associated with the use of Odr do not require a diagnostic message, so you can violate this rule, and the compiler is not required to notify you.
In your case, you really use the odr use of str_ , and you cannot include the definition in the header file because it violates one definiton rule, because it can be included more than once in the program.
It is interesting to note that if you did the following, it would not be used in odr:
return str_.size_;
Therefore, you will not need to define a variable that may have some odd consequences in some examples . I doubt it really solves your problem in the long run.
The odr rules are described in the C ++ 3.2 draft standard section, and they say:
The variable x, whose name is displayed as a potentially evaluated expression ex, is used by odr, if the lvalue-to-rvalue transformation (4.1) is not applied to x, it gives a constant expression (5.19) that does not call any non-trivial functions and, if x is an object, ex - an element is the set of potential results of expression e, where either the lvalue-to-rvalue transformation (4.1) is applied to e or e is the expression of the reset value (paragraph 5). this is used by odr if it appears as a potentially evaluated expression (including as a result of an implicit conversion to the body of a non-static member function (9.3.1)). [...]
So str_ gives a constant expression, the lvalue-to-rale conversion does not apply the str_.size() expression and it is not the discarded value of the expression, therefore it is used as odr and therefore str_ is required to be defined.
On the other hand, the lvalue-to-rvalue transformation is applied to the str_.size_ expression, so it is not used by odr and does not require the definition of str_ .