请考虑以下代码:
#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>);
}
在gcc.gotbolt.org上运行
如果我在这里使用而不是
std::less
,则代码无法编译。 这并不奇怪,因为如果指针指向不相关的对象,关系指针比较的结果是未指定的,而且显然在编译时无法进行这样的比较。
<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>;
^
代码仍然无法编译,即使我使用std::less
。 编译器错误相同。 std::less
似乎至少在libstdc++和libc++中实现为<
; 我在GCC,Clang和msvc上得到了相同的结果。
但是,关于std::less
的cppreference页面声称:
>
的运算符()
是ConstExpr
。
它神奇地在指针上实现了严格的总顺序,即可以用来将不相关的指针与可感的结果进行比较。
那么,是所有这些编译器中的一个bug,还是我遗漏了一些有关std::less
的细节,使得上面的代码格式不正确?
我不认为你所问的问题有一个明确的答案。 这是LWG2833的一个具体情况:标记库函数constexpr
并不能解释调用该函数是否会实际产生常量表达式。
在这个问题得到解决之前,我认为您根本不能指望std::less
能够在编译时比较不相关的指针。
要成为有效的ConstExpr
函数,它应该具有结果为ConstExpr
的参数,而不是所有参数。
例如
constexpr int foo(bool b) { if (!b) throw 42; return 42; }
是有效的,则可以在constexpr中使用f(true)
(即使f(false)
不能)。
constexpr int a[2]{};
constexpr bool b = std::less<const void*>{}(&a[0], &a[1]);
有效并且足以允许less::operator()
为constexpr
。
我认为在标准中没有指定哪些范围/值对constexpr是正确的。
所以所有编译器都是正确的。