I just created a bug by testing a value against the following expression:
std::numeric_limits<decltype(allocationCount)>::max()
In this context, allocationCount
is a std::atomic<std::size_t>
.
Apparently, the above mentioned expression compiles and evaluates to 0 on both Clang 10 and GCC 10:
#include <atomic>
#include <cstdint>
#include <limits>
#include <string>
static std::atomic<std::size_t> allocationCount = 0;
uint64_t buggyGetMax() {
return std::numeric_limits<decltype(allocationCount)>::max();
}
uint64_t correctGetMax() {
return std::numeric_limits<decltype(allocationCount)::value_type>::max();
}
What I meant to use was
std::numeric_limits<decltype(allocationCount)::value_type>::max()
that produces the value I wanted, that is std::numeric_limits<std::size_t>::max()
.
The question I have is why std::numeric_limits<decltype(allocationCount)>
even compiled? Shouldn't it fail as std::numeric_limits<std::string>
does?
If this is by design, why is the max()
0?
This is the default behavior. From [numeric.limits]
- For all members declared static constexpr in the
numeric_limits
template, specializations shall define these values in such a way that they are usable as constant expressions.- The default
numeric_limits<T>
template shall have all members, but with0
orfalse
values.- Specializations shall be provided for each arithmetic type, both floating-point and integer, including bool. The member
is_specialized
shall betrue
for all such specializations ofnumeric_limits
.- The value of each member of a specialization of
numeric_limits
on a cv-qualified type cvT
shall be equal to the value of the corresponding member of the specialization on the unqualified typeT
.- Non-arithmetic standard types, such as
complex<T>
, shall not have specializations.
So, since std::atomic<T>
is a non-arithmetic type, it shall not have a specialization per paragraph 6 and that means paragraph 3 comes into play and all values you get will be 0
or false
.