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_limitstemplate. 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???"
The primary template of
std::numeric_limitsvalue-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_specializedtotrueand must define all members, with sensible values where applicable, or0orfalseotherwise, see [numeric.limits.special]/1 and [numeric.limits.general]/4.Interestingly [numeric.limits.general]/4 requires the standard specializations to set
is_specializedtotrue, but I don't see any equivalent requirement for user specializations.