C++ std::less是否应该允许在编译时比较不相关的指针?
考虑以下代码:C++ std::less是否应该允许在编译时比较不相关的指针?,c++,language-lawyer,std,compile-time,C++,Language Lawyer,Std,Compile Time,考虑以下代码: #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>); } 即
#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>);
}
即使我使用
std::less
,代码仍然无法编译。编译器错误与此相同std::less
似乎被实现为为了有效constepr
函数,它应该具有结果为constepr
的参数,而不是所有参数
比如说
constexpr int foo(bool b) { if (!b) throw 42; return 42; }
有效,f(true)
可以在constexpr中使用(即使f(false)
不能)
constexpr int a[2]{};
constexpr bool b=std::less{}(&a[0],&a[1]);
有效,足以允许less::operator()
成为constepr
我认为标准中没有规定constexpr的正确范围/值
所以所有的编译器都是正确的。我不认为你所问的问题有一个明确的答案。这是一种特殊情况:标记库函数constexpr
并不能解释调用该函数将生成常量表达式的情况
在这个问题解决之前,我认为您不能依赖于std::less
能够在编译时比较不相关的指针代码>,需要一个constexpr变量来满足以下规则:
对象声明中使用的constexpr说明符将对象声明为const。此类对象应具有文字类型,并应初始化。在任何constexpr变量声明中,初始化的完整表达式应为常量表达式。(注意强调的部分)
常量表达式必须是核心常量表达式,因此必须满足核心常量表达式规则:
一个关系运算符或相等运算符,其中结果未指定
在您的代码中,&typeid(int)
和&typeid(float)
未指定,原因是:
将不等指针与对象进行比较的定义如下:
- 如果两个指针指向同一数组的不同元素或其子对象,则指向下标较高的元素的指针比较大
- 如果两个指针递归地指向同一对象的不同非静态数据成员,或指向此类成员的子对象,则如果两个成员具有相同的访问控制且其类不是并集,则指向后一个声明成员的指针会比较大
- 否则,两个指针的比较值都不大于另一个
&typeid(int)
和&typeid(float)
符合第三个项目符号。及
如果两个操作数p和q比较相等,则p=q均为真,而pq均为假。否则,如果一个指针p比较大于一个指针q,p>=q,p>q,qOff主题:在比较之前将两个指针转换为uintptr\t对我来说并不是“神奇的”…@Aconcagua如果这样做,那么就无法找到它(在本节末尾)。如果不使用a
,它可以简单地进行优化。如果你使用它会发生什么?例如,使用返回a?99 : 101 ;
@TonyK即使没有使用变量,代码也不会编译,因此我怀疑如果我以某种方式使用它,代码是否会编译。这如何适用于这个特定问题?@_Static_assert:可能是吹毛求疵,但函数标记为constexpr
(带有常量参数)通常不足以在常量表达式中使用。@HolyBlackCat修改了我的答案。是的,现在它似乎正确地解释了为什么@HolyBlackCat就我所知,它不能,因为整个typeid
是实现定义的,如果操作数是多态类类型,它将是一个运行时值。
constexpr int a[2]{};
constexpr bool b = std::less<const void*>{}(&a[0], &a[1]);