为什么0 ==(“ abcde” +1)不是常数表达式?

时间:2019-01-29 15:11:44

标签: c++ gcc c++14 language-lawyer constexpr

为什么下面的代码不能编译?

// 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。

1 个答案:

答案 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)提供了一些值,这些值在编译时给出了一致的总顺序,并且给出了相同的答案。运行。这是一个有趣的难题。