我正在研究核心常量表达式*中允许的内容,这在C++标准草案的5.19
常量表达式第2段中有所描述:
条件表达式是核心常量表达式,除非它涉及以下之一作为潜在评估的子表达式(3.2),但是未评估的逻辑AND(5.14),逻辑OR(5.15)和条件(5.16)操作的子表达式不考虑[注意:重载的运算符调用函数.-end note]:
并列出随后的子弹中的排除项并包括(强调我的):
- 具有未定义行为的操作 [注意:包括,例如,有符号整数溢出(第5条),某些指针算术(5.7),除零(5.6)或某些移位操作(5.8) - 结束注释];
嗯?为什么常量表达式需要此子句来涵盖未定义的行为?常量表达式是否有一些特殊的东西需要未定义的行为才能在排除中进行特殊划分?
拥有这个条款是否给了我们没有它的任何优势或工具?
作为参考,这看起来像广义常量表达式提案的最新修订版.
这是有效的,因为一个constexpr
表达式被允许取的值"文字类型的glvalue其指的是与constexpr定义的非挥发性物体,或者是指这样的对象的一个子对象"(§5.19/ 2 ):
constexpr char str[] = "hello, world";
constexpr char e = str[1];
Run Code Online (Sandbox Code Playgroud)
但是,似乎字符串文字不符合此描述:
constexpr char e = "hello, world"[1]; // error: literal is not constexpr
Run Code Online (Sandbox Code Playgroud)
2.14.5/8描述了字符串文字的类型:
普通字符串文字和UTF-8字符串文字也称为窄字符串文字.窄字符串文字具有类型"n const char数组",其中n是下面定义的字符串的大小,并且具有静态存储持续时间.
看起来这种类型的对象可以被索引,只要它是临时的而不是静态存储持续时间(5.19/2,就在上面的代码片段之后):
[
constexpr
允许lvalue-to-rvalue转换] ...一个文字类型的glvalue,引用一个非易失性临时对象,其生命周期尚未结束,用一个常量表达式初始化
这是特别奇怪的,因为取一个临时对象的左值通常是"作弊".我想这个规则适用于引用类型的函数参数,例如in
constexpr char get_1( char const (&str)[ 6 ] )
{ return str[ 1 ]; }
constexpr char i = get_1( { 'y', 'i', 'k', 'e', 's', '\0' } ); // OK
constexpr char e = get_1( "hello" ); // error: string …
Run Code Online (Sandbox Code Playgroud) 我们都听过警告,如果你在C或C++中调用未定义的行为,任何事情都可能发生.
这是否仅限于任何运行时行为,还是包括任何编译时行为?特别是,编译器在遇到调用未定义行为的构造时,允许拒绝代码(在标准中没有其他要求的情况下这样做),甚至崩溃?
在编译阶段扩展UB的原因是什么?遇到UB代码时,不是编译和链接二进制文件,而是让二进制文件服从UB?(如果不可能生成二进制文件,那么只需打印一条关于它的错误消息.)
毕竟,我们期望从编译器的最确切的报告汇编即使在源代码中包含UB-代码(几乎每件的源代码可能包含一些UB-代码).
您能给这样的UB-代码一个具体的例子,这确实更有道理,让编译器表现出UB比让生成的二进制表现出UB?
这个问题源于这一点:"未定义的行为"是否扩展到编译时?