当前位置: 首页 > 知识库问答 >
问题:

int a=1,||1是常量表达式吗?

沈嘉瑞
2023-03-14

N4527 5.20【expr.const】p5

常量表达式是glvalue核心常量表达式,其值是指常量表达式(定义如下)的允许结果实体,或者是prvalue核心常量表达式,其值是对象,其中,对于该对象及其子对象:

-引用类型的每个非静态数据成员引用一个实体,该实体是常量表达式的允许结果,并且

-如果对象或子对象是指针类型,则它包含具有静态存储持续时间的对象的地址、超过此类对象结尾的地址(5.7)、函数的地址或空指针值。

如果实体是具有静态存储持续时间的对象,而该对象不是临时对象,或者是值满足上述约束的临时对象,或者是函数,则实体是常量表达式的允许结果。

void foo(){
    int a = 1;
    int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
    static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
    switch(1){
        case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
            ;
        }
}

是一个常量表达式吗?

N4527 5.20[膨胀常数]p2

条件表达式e是一个核心常量表达式,除非根据抽象机器(1.9)的规则对e求值将求值以下表达式之一:

(2.7)-左值-右值转换(4.1),除非它应用于

(2.7.1)-整数或枚举类型的非易失性glvalue,指的是具有先前初始化、使用常量表达式初始化的完整非易失性常量对象,或

(2.7.2)-非易失性glvalue,它引用字符串文字(2.13.5)的子对象,或

(2.7.3)-一个非易失性glvalue,它指的是一个非易失性对象,或者指的是这样一个对象的一个不可变的子对象,或者

(2.7.4)-文字类型的非易失性glvalue,指的是寿命开始于e评估范围内的非易失性对象;

是核心常量表达式吗?

共有3个答案

宓英哲
2023-03-14

如果编译器检查整个赋值链,那么它可以确定“a||1”是一个常量表达式。但是,由于a是一个变量,除非编译器检查a没有被赋值,否则它无法知道“a||1”是一个常量表达式。

葛昱
2023-03-14

重复您的报价:

(2.7)-左值-右值转换(4.1),除非它应用于

(2.7.1)-整数或枚举类型的非易失性glvalue,指的是具有先前初始化、使用常量表达式初始化的完整非易失性常量对象,或

a涉及左值-右值转换。由于a不是const对象,这意味着a不是核心常量表达式;因此a||1也不是。

但是,如果您的代码是:

const int a = 1;

那么a | | 1将是一个核心常量表达式。

轩辕亮
2023-03-14

<代码>a 不是常量表达式(请参见下面的标准引号),因此:

a || 1 

也不是一个常量表达式,虽然我们知道表达式必须求值为true,但这里的标准要求从左到右求值,我看不到允许编译器跳过a的左值到右值转换的例外。

但是:

const int a = 1;

可以在常量表达式中使用,因为它属于5.20p2的异常(emphasis mine):

左值到右值的转换(4.1),除非应用于

  • 整型或枚举型的非易失性glvalue,它引用了一个完整的非易失性常量对象,该对象具有前面的初始化、用常量表达式初始化或

这条规则也是为什么原始case不是常量表达式的原因,因为没有一个异常适用。

也许gcc允许这样做:

int b[a || 1]{};

作为可变长度数组的扩展,尽管它应该使用pedantic提供警告。虽然这不能解释static\u assert的情况,但它们可以是常量折叠它,但我认为“好像”规则不允许将其视为常量表达式

更新,可能的gcc扩展

根据此错误报告,逻辑运算符的RHS可能会使LHS在常量表达式中未赋值,这看起来像是一个可能的gcc扩展:

尽管在常量表达式中使用了非常量对象,但编译时不会发生意外:

int i;
static_assert( i || true, "" );
static_assert( ! ( i && false ), "" );

似乎是假设| |和

最后的评论是:

我认为这是一个有目的的语言扩展,可以使用开关禁用。如果static\u断言总是严格的,那就太好了。

这似乎是一个不一致的扩展,当使用pedantic标志时,它会触发一个警告,类似于在将非constexpr标准库函数视为constexpr?中发出的一致性编译器扩展?。

C 11/C 14报价

第5.20节是C 14和C 11中的第5.19节,C 14标准草案中的相关引用是:

左值到右值的转换(4.1),除非应用于

>

  • 整数或枚举类型的非易失性glvalue,它引用具有先前初始化的非易失性const对象,使用常量表达式初始化[注意:字符串文字(2.14.5)对应于此类对象的数组。-结束注释],或

    一个非易失性glvalue,它指的是一个非易失性对象,或者指的是这样一个对象的一个不可变的子对象,或者

    一个文本类型的非易失性glvalue,它指的是一个非易失性对象,其生存期开始于对e的求值;

    对于C 11草案,标准为:

    左值到右值的转换(4.1),除非应用于

    >

    一个文字类型的glvalue,它引用了一个非易失性对象,或者引用了这样一个对象的子对象,或者

    文字类型的glvalue,指的是生命周期尚未结束的非易失性临时对象,用常量表达式初始化;

  •  类似资料:
    • 问题内容: 我需要寻找java regex模式,该模式以1 = 1的格式查找输入字符串,其中前缀“ =”应具有与后缀相同的位数。同样,这里的前缀和后缀值应相同,例如1 = 1、11 = 11、223 = 223。像1 = 2、3 = 22、33 = 22之类的值不应与模式匹配 我们能否有一个满足上述规则的一般模式。 问题答案: 使用反向引用: 当然,在Java中,您需要转义反斜杠:

    • 问题内容: 以下在我的Eclipse中可以正常编译: Java甚至一开始就阻止了许多“愚蠢的代码”的编译(例如,没有编译!),所以它甚至没有产生像警告一样多的事实,这令我感到非常惊讶。当您考虑允许在编译时优化常量表达式这一事实时,这种兴趣就加深了: 上面的代码段在Eclipse中编译,生成了以下字节码() 如您所见,和分配被优化为编译时常量,但是除法(必须在编译时可检测到)被简单地按原样编译。 它

    • 常量表达式机制是为了: 提供一种更加通用的常量表达式 允许用户自定义的类型成为常量表达式 提供了一种保证在编译期完成初始化的方法(可以在编译时期执行某些函数调用) 考虑下面这段代码: enum Flags { good=0, fail=1, bad=2, eof=4 }; constexpr int operator|(Flags f1, Flags f2) { return Flags(int(

    • 序:世界上信息非常多,而我们关注的信息有限。假如我们希望只提取出关注的数据,此时可以通过一些表达式进行提取,正则表达式就是其中一种进行数据筛选的表达式。 正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符")。 正则表达式通常被用来匹配、检索、替换和分割那些符合某个模式(规则)的文本。 Python 自1.5版本起

    • 问题内容: 我在switch / case语句中遇到问题。该错误显示:“ case表达式必须是常量表达式”。我理解该错误,可以使用If来解决它,但是有人可以告诉我为什么case表达式在switch / case中必须是常量。我的错误的代码示例: 谢谢你的解释!! 问题答案: 因此可以在编译阶段进行评估(静态检查) 请参阅:http://docs.oracle.com/javase/specs/jl

    • 我有一个调度程序作业,我已经将配置为cron表达式,每半n小时运行一次,但是调度程序没有被触发,相反,如果我像那样每5分钟设置一次表达式,它就可以正常工作。这里可能有什么问题?我的cron表达式正确吗? 注意:我正在使用Quartz调度器(Java)并在数据库调度器表中创建一个条目。