为什么 0 == ("abcde"+1) 不是常量表达式?
Why is 0 == ("abcde"+1) not a constant expression?
为什么下面的代码不能编译?
// source.cpp
int main()
{
constexpr bool result = (0 == ("abcde"+1));
}
编译命令:
$ g++ -std=c++14 -c source.cpp
输出:
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));
~~~^~~~~~~~~~~~~~~
我正在使用 gcc6.4。
对常量表达式中可以使用的内容的限制主要定义为否定列表。有很多东西是不允许计算的(C++14 中的[expr.const]/2 in C++14) and certain things that values have to result in ([expr.const]/4)。此列表从一个标准变为另一个标准,随着时间的推移变得更加宽松。
在尝试评估:
constexpr bool result = (0 == ("abcde"+1));
没有什么是我们不允许评估的,我们没有任何我们不允许的结果。没有未定义的行为等。它是一个完全有效的表达式,即使很奇怪。只是 gcc 6.3 碰巧不允许的一个 - 这是一个编译器错误。 gcc 7+, clang 3.5+, msvc 都可以编译。
关于这个问题似乎有很多困惑,许多评论表明,由于像 "abcde"
这样的字符串文字的值直到运行时才知道,所以你不能在运行期间对这样的指针做任何事情不断的评估。解释为什么这不是真的很重要。
让我们从这样的声明开始:
constexpr char const* p = "abcde";
这个指针有一些值。假设 N
。关键是 - 在不断评估 期间,你试图观察 N
所做的任何事情都是病式的。你不能 cast it to an integer to read the value. You cannot compare it to a different, unrelated string† (by way of [expr.rel]/4.3):
constexpr char const* q = "hello";
p > q; // ill-formed
p <= q; // ill-formed
p != q; // ok, false
我们可以肯定地说p != q
,因为它们指向的地方明显不同。但我们不能说哪个先行。这样的比较是未定义的行为,常量表达式中的未定义行为is disallowed。
你真的可以只比较同一数组中的指针:
constexpr char const* a = p + 1; // ok
constexpr char const* b = p + 17; // ill-formed
a > p; // ok, true
无论 p
指向哪里,我们 知道 a
指向它后面。但是我们不需要知道 N
来确定这一点。
因此,持续评估期间的实际值 N
或多或少并不重要。
"abcde"
是……某处。 "abcde"+1
指向比它晚的一个,并且具有值 "bcde"
。无论它指向何处,您都可以将它与空指针进行比较(0
是一个空指针常量)并且它不是空指针,因此该比较结果为 false。
这是一个格式正确的常量求值,gcc 6.3 碰巧拒绝了它。
†尽管我们简单地声明 std::less()(p, q)
提供了一些值,在编译时给出了一致的总顺序 and 它在运行时给出了相同的答案。这是……一个有趣的难题。
为什么下面的代码不能编译?
// source.cpp
int main()
{
constexpr bool result = (0 == ("abcde"+1));
}
编译命令:
$ g++ -std=c++14 -c source.cpp
输出:
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));
~~~^~~~~~~~~~~~~~~
我正在使用 gcc6.4。
对常量表达式中可以使用的内容的限制主要定义为否定列表。有很多东西是不允许计算的(C++14 中的[expr.const]/2 in C++14) and certain things that values have to result in ([expr.const]/4)。此列表从一个标准变为另一个标准,随着时间的推移变得更加宽松。
在尝试评估:
constexpr bool result = (0 == ("abcde"+1));
没有什么是我们不允许评估的,我们没有任何我们不允许的结果。没有未定义的行为等。它是一个完全有效的表达式,即使很奇怪。只是 gcc 6.3 碰巧不允许的一个 - 这是一个编译器错误。 gcc 7+, clang 3.5+, msvc 都可以编译。
关于这个问题似乎有很多困惑,许多评论表明,由于像 "abcde"
这样的字符串文字的值直到运行时才知道,所以你不能在运行期间对这样的指针做任何事情不断的评估。解释为什么这不是真的很重要。
让我们从这样的声明开始:
constexpr char const* p = "abcde";
这个指针有一些值。假设 N
。关键是 - 在不断评估 期间,你试图观察 N
所做的任何事情都是病式的。你不能 cast it to an integer to read the value. You cannot compare it to a different, unrelated string† (by way of [expr.rel]/4.3):
constexpr char const* q = "hello";
p > q; // ill-formed
p <= q; // ill-formed
p != q; // ok, false
我们可以肯定地说p != q
,因为它们指向的地方明显不同。但我们不能说哪个先行。这样的比较是未定义的行为,常量表达式中的未定义行为is disallowed。
你真的可以只比较同一数组中的指针:
constexpr char const* a = p + 1; // ok
constexpr char const* b = p + 17; // ill-formed
a > p; // ok, true
无论 p
指向哪里,我们 知道 a
指向它后面。但是我们不需要知道 N
来确定这一点。
因此,持续评估期间的实际值 N
或多或少并不重要。
"abcde"
是……某处。 "abcde"+1
指向比它晚的一个,并且具有值 "bcde"
。无论它指向何处,您都可以将它与空指针进行比较(0
是一个空指针常量)并且它不是空指针,因此该比较结果为 false。
这是一个格式正确的常量求值,gcc 6.3 碰巧拒绝了它。
†尽管我们简单地声明 std::less()(p, q)
提供了一些值,在编译时给出了一致的总顺序 and 它在运行时给出了相同的答案。这是……一个有趣的难题。