为什么下面的代码不能编译?
// 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。
答案 0 :(得分:16)
对可以在常量表达式中使用的内容的限制主要定义为负数列表。有很多事情是您不允许评估的(在C ++ 14中为[expr.const]/2),某些事情是必须要值的(在C ++ 14中是[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读取值。您无法将其与a different, unrelated string†(通过[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)
提供了一些值,这些值在编译时给出了一致的总顺序,并且给出了相同的答案。运行。这是一个有趣的难题。