c++ - 在 constexpr 中使用 argc,是否严格要求所涉及的任何子表达式都是常量表达式?

标签 c++ c++11 gcc language-lawyer constexpr

例子:

int main(int argc, char**)
{
    constexpr int a = argc * 0;
    (void)a;
    constexpr int b = argc - argc;
    (void)b;
    return 0;
}

argc 不是常量表达式,但编译器仍然能够在编译时计算出 ab 的结果(即0) 在这两种情况下。

g++接受上面的代码,而 clang并且 MSVC14 拒绝它。

标准是否允许编译器在 constexpr 方面像 g++ 一样智能?

最佳答案

argc * 0argc - argc 都不是常量表达式,在某些情况下允许左值到右值的转换,它们都不适用于此处。如果我们查看 C++11 标准草案 5.19 [expr.const],它列出了异常(exception)情况。它说:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [...]

并且有几个项目符号,包括以下关于左值到右值转换的内容:

an lvalue-to-rvalue conversion (4.1) unless it is applied to

  • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or

  • a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or

  • a glvalue of literal type that refers to a non-volatile temporary object whose lifetime has not ended, initialized with a constant expression;

有趣的是,gcc 不接受以下代码 ( see it live ):

constexpr int a = argc * 2;

所以看起来 gcc 是说我知道结果将为零,因此它执行常量折叠并且不需要执行 argc 的左值到右值转换来确定结果.

不幸的是,我在 5.19 部分没有看到任何允许这种短路的规定。这看起来与 int a=1, is a || 1 a constant expression? 中的案例非常相似它有一个错误报告,但 gcc 团队没有人回复那个报告。我添加了一个 comment那个错误报告表明这似乎是相关的。

Mark 在下面的评论表明这是一个错误:

There is a whole c++-delayed-folding branch on which some gcc developers are working, which will delay a number of optimizations and might fix this. It is important for other reasons, rejecting the code in this question is very low priority

常量表达式是否严格要求每个子表达式都是常量表达式?不,例如 5.19 它说:(emphasis mine)

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional (5.16) operations that are not evaluated are not considered [...]

所以下面是一个常量表达式:

constexpr int a = false && argc * 0;

因为 argc * 0 没有计算,因为 && 计算从左到右和短路。

关于c++ - 在 constexpr 中使用 argc,是否严格要求所涉及的任何子表达式都是常量表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32920229/

相关文章:

c++11 - 如何使用 travis-ci 使用现代 cmake 构建现代 c++?

c++ - 将图像放在另一个图像上

c++ - win32 CreateThread,如何将lpStartAddress参数作为c++类函数调用?

C++:为什么我们可以将函数返回的 vector 中的元素绑定(bind)到非常量左值引用?

c++ - 与 C++ 2011 不相关的并行随机种子?

c++ - 了解返回时的右值引用

gcc - 栈分配,为什么要多出空间?

c - 为什么 char* 类型转换对于获取变量的大小很重要?

c++ - 单声道嵌入: How to access type of a property in C/C++

c++ - 浮点类型表示