【问题标题】:Why is 0 == ("abcde"+1) not a constant expression?为什么 0 == ("abcde"+1) 不是常量表达式?
【发布时间】:2019-06-22 18:12:24
【问题描述】:

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

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

【问题讨论】:

  • 哦,真的吗?现在我很困惑......这应该做什么? Afaik 你永远无法通过向指针添加内容获得0
  • GCC 7.x 及更高版本编译您的代码没有任何错误(带有-std=c++14 -pedantic-errors 标志)。 Clang 和 MSVC 也没有抱怨。可能是 GCC 6 错误?
  • @user463035818 当然表达式是false,OP 不反对。问题是为什么它不能编译。
  • godbolt.org/z/oYNZIQ 重现错误。如果将"abcd" 替换为&"abcd"[0],它可以工作(甚至是内联的)。无论出于何种原因,const char[] -> const char* 衰减似乎都不算作constexpr

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


【解决方案1】:

对常量表达式中可以使用的内容的限制主要定义为否定列表。有很多东西是不允许评估的(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 都可以编译。


围绕这个问题似乎有很多混淆,许多 cmets 建议由于像 "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) 提供了一些值,在编译时给出了一致的总顺序并且它在运行时给出了相同的答案。这是……一个有趣的难题。

【讨论】:

  • 感谢您的回答!您能否添加对标准的引用,以确认比较 p > q 是不正确的?
  • 我们实际上并没有这么说。我们只说函数调用运算符是constexpr,这几乎没有意义,因为我们实际上并没有说对于哪些参数它是一个常量子表达式。
  • @Barry 你说“像“abcde”这样的字符串文字的值直到运行时才知道”是什么意思?我想它是已知的,例如我们可以在编译期间计算它的任何子字符串。对吗?
  • @embedc 我正在解释发布在各种答案中的六个其他 cmets - 这表明 pointer 的值(特定地址)直到运行时才知道。然后我解释为什么这并不意味着你根本不能使用指针。
  • 好吧,通过说“因为像“abcde”这样的字符串文字的值直到运行时才知道”,你听起来就像像“abcde”这样的字符串文字的值在编译之前真的是未知的时间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-13
  • 2022-10-08
  • 2011-11-15
  • 2019-06-22
  • 1970-01-01
  • 2014-08-26
  • 1970-01-01
相关资源
最近更新 更多