emb*_*edc 20 c++ gcc language-lawyer constexpr c++14
为什么下面的代码没有编译?
// source.cpp
int main()
{
constexpr bool result = (0 == ("abcde"+1));
}
Run Code Online (Sandbox Code Playgroud)
编译命令:
$ g++ -std=c++14 -c source.cpp
Run Code Online (Sandbox Code Playgroud)
输出:
source.cpp: In function ‘int main()’:
source.cpp:4:32: error: ‘((((const char*)"abcde") + 1u) == 0u)’ is not a constant expression
constexpr bool result = (0 == ("abcde"+1));
~~~^~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)
我正在使用gcc6.4.
Bar*_*rry 16
可以在常量表达式中使用的限制主要定义为否定列表.有一些你不被允许评估的东西(C++ 14中的[expr.const]/2)和值必须导致的某些东西(C++ 14中的[expr.const]/4).此列表从标准更改为标准,随着时间变得更加宽松.
在试图评估:
constexpr bool result = (0 == ("abcde"+1));
Run Code Online (Sandbox Code Playgroud)
没有什么我们不被允许评估,我们没有任何我们不允许的结果.没有未定义的行为等.这是一个完全有效的,如果奇怪的表达式.只是一个gcc 6.3碰巧不允许 - 这是一个编译器错误.gcc 7+,clang 3.5+,msvc都编译它.
围绕这个问题似乎存在很多混淆,许多评论表明,由于字符串文字的值"abcde"
直到运行时才知道,所以在常量评估期间你不能对这样的指针做任何事情.解释为什么这不是真的很重要.
让我们从如下声明开始:
constexpr char const* p = "abcde";
Run Code Online (Sandbox Code Playgroud)
这个指针有一些价值.让我们说吧N
.至关重要的是 - N
在不断的评估过程中,你可以做的任何事情都是不正确的.您不能将其强制转换为整数来读取值.你无法将它与不同的,无关的字符串†(通过[expr.rel] /4.3)进行比较:
constexpr char const* q = "hello";
p > q; // ill-formed
p <= q; // ill-formed
p != q; // ok, false
Run Code Online (Sandbox Code Playgroud)
我们可以肯定地说,p != q
因为无论它们指向何处,它们都明显不同.但我们不能说哪一个先行.这种比较是未定义的行为,并且在常量表达式中不允许使用未定义的行为.
你真的只能比较同一个数组中的指针:
constexpr char const* a = p + 1; // ok
constexpr char const* b = p + 17; // ill-formed
a > p; // ok, true
Run Code Online (Sandbox Code Playgroud)
无论p
指向何处,我们都知道它a
之后的点.但我们不需要知道N
确定这一点.
结果,N
在持续评估期间的实际值或多或少是无关紧要的.
"abcde"
是...在某个地方."abcde"+1
指向一个晚于此,并具有价值"bcde"
.无论它指向何处,您都可以将其与空指针(0
是空指针常量)进行比较,并且它不是空指针,因此该比较的计算结果为false.
这是一个非常完善的常量评估,gcc 6.3恰好拒绝了.
†虽然我们只是通过命令std::less()(p, q)
提供一些值,该值提供了一些在编译时提供一致的总顺序的值,并且它在运行时给出了相同的答案.这是......一个有趣的难题.
归档时间: |
|
查看次数: |
658 次 |
最近记录: |