Consider this code:
#include <functional>
#include <typeinfo>
template <typename T>
inline constexpr const void *foo = &typeid(T);
int main()
{
constexpr bool a = std::less<const void*>{}(foo<int>, foo<float>);
}
If I use <
instead of std::less
here, the code doesn't compile. This is not surprising, because the result of a relational pointer comparsion is unspecified if the pointers point to unrelated objects, and apparently such a comparsion can't be done at compile-time.
<source>:9:20: error: constexpr variable 'a' must be initialized by a constant expression constexpr bool a = foo<int> < foo<float>; ^ ~~~~~~~~~~~~~~~~~~~~~ <source>:9:33: note: comparison has unspecified value constexpr bool a = foo<int> < foo<float>; ^
The code still doesn't compile, even if I use std::less
. The compiler error is the same. std::less
appears to be implemented as <
in at least libstdc++ and libc++; I get the same results on GCC, Clang, and MSVC.
However, the cppreference page about std::less
claims that:
Its operator()
is constexpr
.
It magically implements strict total order on pointers, i.e. can be used to compare unrelated pointers with sensible results.
So, is it a bug in all those compilers, or am I missing some detail about std::less
that makes the code above ill-formed?
I don't think there's a clear answer to the question that you're asking. This is a specific case of LWG 2833: marking a library function constexpr
does not explain the circumstances under which calling the function will yield a constant expression.
Until this issue is resolved, I think you simply cannot rely on std::less
being able to compare unrelated pointers at compile time.