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

前端之家收集整理的这篇文章主要介绍了c – 在constexpr中使用argc,是否严格要求所涉及的任何子表达式都是常量表达式?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
例:
int main(int argc,char**)
{
    constexpr int a = argc * 0;
    (void)a;
    constexpr int b = argc - argc;
    (void)b;
    return 0;
}

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

g++接受上面的代码,而clang和MSVC14拒绝它.

标准是否允许编译器在constexpr方面与g一样聪明?

解决方法

argc * 0和argc – argc都不是常量表达式,在某些情况下允许左值到右值的转换,这些都不适用于此处.如果我们查看草案C 11标准第5.19节[expr.const],它会列出例外情况.它说:

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,表明这似乎是相关的.

马克的评论如下表明这是一个错误

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它说:(强调我的)

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&C++相关文章