c++language-lawyernumeric-limits

What does std::numeric_limits do for types that don't specialize it?


This code compiles and runs

#include <limits>
#include <iostream>

struct Foo {
    int x;
};

static_assert(!std::numeric_limits<Foo>::is_specialized);

int main() {
    std::cout << "---" << std::endl;
    std::cout << std::numeric_limits<Foo>::lowest().x << std::endl;
    std::cout << std::numeric_limits<Foo>::min().x << std::endl;
    std::cout << std::numeric_limits<Foo>::max().x << std::endl;
    std::cout << "---" << std::endl;
}

and it prints

---
0
0
0
---

Where are those numbers coming from?

On cppreference I read that

This information is provided via specializations of the std::numeric_limits template. The standard library makes available specializations for all arithmetic types

from which I'd deduce that the absence of a specialization for a given type Foo means that I'm not allowed to use it for Foo. So is the above output just a manifestation of UB? Or what?

If I change int to char in the code above, the output is

---
---

which to me is "What?! Where have the std::endls gone, to start with???"


Solution

  • The primary template of std::numeric_limits value-initializes all members or return values from member functions, see [numeric.limits.general]/3. So that is what you get if the template isn't specialized for the provided type. There is no UB.

    Any specialization should set is_specialized to true and must define all members, with sensible values where applicable, or 0 or false otherwise, see [numeric.limits.special]/1 and [numeric.limits.general]/4.

    Interestingly [numeric.limits.general]/4 requires the standard specializations to set is_specialized to true, but I don't see any equivalent requirement for user specializations.