std::less 是否应该允许在编译时比较不相关的指针?

Hol*_*Cat 39 c++ std compile-time language-lawyer

考虑这个代码:

#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>);
} 
Run Code Online (Sandbox Code Playgroud)

Run on gcc.gotbolt.org

如果我使用<而不是std::less这里,代码不会编译。这并不奇怪,因为如果指针指向不相关的对象,则关系指针比较的结果是未指定的,而且显然这样的比较不能在编译时完成。

#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>);
} 
Run Code Online (Sandbox Code Playgroud)

即使我使用std::less. 编译器错误是一样的。std::less似乎<至少在 libstdc++ 和 libc++ 中实现;我在 GCC、Clang 和 MSVC 上得到了相同的结果。

但是,关于 cppreference 的页面std::less声称:

  1. operator()constexpr

  2. 它神奇地在指针上实现了严格的全序,即可用于将不相关的指针与合理的结果进行比较。

那么,它是所有这些编译器中的一个错误,还是我遗漏了一些关于std::less使上面的代码格式错误的细节?

Bri*_*ian 28

我认为您提出的问题没有明确的答案。这是LWG 2833 的一个特例:标记库函数constexpr并不能解释在何种情况下调用该函数会产生一个常量表达式。

在这个问题得到解决之前,我认为你不能依赖于std::less能够在编译时比较不相关的指针。


Jar*_*d42 6

要成为有效的constexpr函数,它应该具有结果为 的参数,而constexpr不是所有参数。

例如

constexpr int foo(bool b) { if (!b) throw 42; return 42; }
Run Code Online (Sandbox Code Playgroud)

有效,f(true)可以在 constexpr 中使用(即使f(false)不能)。

constexpr int a[2]{};
constexpr bool b = std::less<const void*>{}(&a[0], &a[1]);
Run Code Online (Sandbox Code Playgroud)

是有效的,就足以让less::operator()constexpr

我认为没有指定标准中的 constexpr 哪些范围/值是正确的。

所以所有的编译器都是正确的。

  • 这如何适用于这个具体问题? (5认同)