50

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?

2
  • 7
    By definition any user-defined type (UDT) is not a fundamental type. Commented Apr 20, 2013 at 17:06
  • 8
    It says "non-fundamental standard types" shall not have specializations. So for non-standard types it would be ok (when it makes sense). Commented Apr 20, 2013 at 17:45

2 Answers 2

43

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.

Sign up to request clarification or add additional context in comments.

6 Comments

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?
This is not about explicitly specializing a member function, but the whole class template.
"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.
@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.
Please explain why one of the many template argument resolution mechanisms wouldn't use a specialization of std::numeric_limits<T> for instantiations using cv-qualified T.
|
29

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
    };
}

3 Comments

Excellent answer. Could you elaborate how to extend this solution for templated templated classes? E.g., if I have template <typename T> struct WrapperAroundT { T m_data; }; and I really want numeric_limit<WrapperAroundT> to apply on the underlying T
You really want this to be a constexpr function
@HappyGreenKidNaps I believe you can just template<typename T> class ::std::numeric_limits< WrapperAroundT< T > > : public ::std::numeric_limits<T> { }; and that should do it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.