The documentation of std::numeric_limits<T>
says it should not be specialized for non-fundamental types. What about number-like user-defined types? If I define my own type T
which represents a numeric value and overloads numeric operators, and for which the information represented by numeric_limits
makes sense -- will anything break if I specialize numeric_limits
for that type?

- 10,885
- 1
- 36
- 58

- 696
- 5
- 8
-
7By definition any user-defined type (UDT) is *not* a fundamental type. – Daniel Frey Apr 20 '13 at 17:06
-
8It says "non-fundamental standard types" shall not have specializations. So for non-standard types it would be ok (when it makes sense). – Bo Persson Apr 20 '13 at 17:45
2 Answers
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
.

- 10,885
- 1
- 36
- 58
-
To me, this reads like a contradiction to 17.6.4.2.1/2: *"The behavior of a C++ program is undefined if it declares an explicit specialization of any member function of a standard library class template"*. What am I missing? – IInspectable Mar 05 '14 at 02:54
-
This is not about explicitly specializing a **member function**, but the whole class template. – danielschemmel Mar 05 '14 at 23:41
-
4"Such a specialization [...] results in undefined behavior unless [...] the specialization meets the standard library requirements for the original template." The original requirements only apply to arithmetic types, suggesting that user specializations may have undefined behavior. – Richard Smith Oct 24 '14 at 16:32
-
@RichardSmith If you can substantiate the fact that the original requirements have an implicit "must be an arithmetic type" somewhere, I might be inclined to believe you. However, as far as I remember (the last edit to this question was may '13), nothing in the standards mandates this. – danielschemmel Oct 31 '14 at 18:42
-
Please explain why one of the many template argument resolution mechanisms wouldn't use a specialization of `std::numeric_limits
` for instantiations using cv-qualified T. – Spencer May 25 '16 at 13:59 -
@Spencer Because e.g. `int const` and `int` are two different types, which [will cause the default to be chosen](http://ideone.com/pJsvpr). There are basically no additional resolution mechanisms when passing a template type parameter directly (unlike what happens when passing an ordinary argument to a function template w/o explicitly specifying the template parameters). – danielschemmel May 30 '16 at 02:34
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
};
}

- 18,496
- 11
- 65
- 106
-
Excellent answer. Could you elaborate how to extend this solution for templated templated classes? E.g., if I have `template
struct WrapperAroundT { T m_data; };` and I really want `numeric_limit – Happy Green Kid Naps Jul 04 '20 at 21:26` to apply on the underlying T -
2
-
@HappyGreenKidNaps I believe you can just `template
class ::std::numeric_limits< WrapperAroundT< T > > : public ::std::numeric_limits – Tim Aug 31 '23 at 09:50{ };` and that should do it