is it ok to specialize std::numeric_limits<T> for user-defined number-like classes?
Solution 1:
Short answer:
Go ahead, nothing bad will happen.
Long answer:
The C++ standard extensively protects the ::std
namespace in C++11 17.6.4.2.1, but specifically allows your case in paragraphs 1 and 2:
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
[...] A program may explicitly instantiate a template defined in the standard library only if the declaration depends on the name of a user-defined type and the instantiation meets the standard library requirements for the original template.
The older C++03 has a similar definition in 17.4.3.1/1:
It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template.
After getting past this fundamental stepping stone, you already pointed out, C++03 18.2.1/4 forbids specializations of ::std::numeric_limits
for certain types:
Non-fundamental standard types, such as complex (26.2.2), shall not have specializations.
The more current C++11 18.3.2.1/4 has a slightly different wording:
Non-arithmetic standard types, such as
complex<T>
(26.4.2), shall not have specializations.
Both of these formulations however allow specializations for non-standard types, which T
is, since you defined it yourself (as @BoPersson already pointed out in the comments).
Caveats
C++11 18.3.2.3/1 hints that you should (but does not require you to) ensure that your specialization has all members.
Also, you may wish to ensure that C++11 18.3.2.3/2 is not violated by your specialization:
The value of each member of a specialization of numeric_limits on a cv-qualified type cv T shall be equal to the value of the corresponding member of the specialization on the unqualified type T.
Which essentially means, that if you wish to specialize it for T
, you should also do so for T const
, T volatile
and T const volatile
.
Solution 2:
Just an example:
namespace std {
template<> class numeric_limits<Temperature> {
public:
static Temperature lowest() {return Temperature(-273.15f);};
// One can implement other methods if needed
};
}