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::endl
s gone, to start with???"
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.