C++ 字符串文字是否可以在常量表达式中下标?

C++ 字符串文字是否可以在常量表达式中下标?,c++,c++11,string-literals,constexpr,C++,C++11,String Literals,Constexpr,这是有效的,因为constexpr表达式允许采用“引用使用constexpr定义的非易失性对象或引用此类对象的子对象的文字类型的glvalue”的值(§5.19/2): 但是,字符串文字似乎不符合以下描述: constexpr char e = "hello, world"[1]; // error: literal is not constexpr 2.14.5/8描述了字符串文字的类型: 普通字符串文字和UTF-8字符串文字也称为窄字符串文字。窄字符串文字的类型为“array of n c

这是有效的,因为
constexpr
表达式允许采用“引用使用constexpr定义的非易失性对象或引用此类对象的子对象的文字类型的glvalue”的值(§5.19/2):

但是,字符串文字似乎不符合以下描述:

constexpr char e = "hello, world"[1]; // error: literal is not constexpr
2.14.5/8描述了字符串文字的类型:

普通字符串文字和UTF-8字符串文字也称为窄字符串文字。窄字符串文字的类型为“array of n const char”,其中n是下面定义的字符串大小,具有静态存储持续时间

这种类型的对象似乎可以被索引,只要它是临时的,不具有静态存储持续时间(5.19/2,就在上述代码段之后):

[
constexpr
允许左值到右值的转换]…一个文本类型的glvalue,它引用一个非易失性的临时对象,其生存期尚未结束,并用常量表达式初始化

这尤其奇怪,因为获取临时对象的左值通常是“欺骗”的

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 literal not temporary
值得一提的是,GCC4.7接受了
get_1(“hello”)
,但拒绝了
“hello”[1]
,因为“.\u 0”的值在常量表达式中不可用”……但是
“hello”[1]
可以作为大小写标签或数组绑定

我在这里分了一些标准的头发…分析正确吗?这个功能有什么设计意图吗

编辑:哦……这是有动机的。这种表达式似乎是在预处理器中使用查找表的唯一方法。例如,这会引入一个代码块,除非
SOME\u INTEGER\u FLAG
为1或5,否则该代码块将被忽略,如果大于6,则会导致诊断:

#if "\0\1\0\0\0\1"[ SOME_INTEGER_FLAG ]

这个构造对于C++11来说是新的。

目的是这样做,并且当左值到右值转换有效时,说明左值的段落将说明引用字符串文字的子对象的左值是用常量表达式初始化的常量整型对象(这被描述为允许的情况之一)在后C++11草案中


你关于预处理器使用的评论看起来很有趣,但我不确定这是否有效。这是我第一次听到的。

关于您关于
#if
的问题,标准委员会无意增加可在预处理器中使用的表达式集,当前的措辞被认为是一个缺陷。这将被列为核心问题1436后科纳WG21邮寄。谢谢你让我们注意到这一点

我认为注释是不规范的,为什么要注释?我认为重点是措辞已经支持这种解释,只是不够明显,存在疑问;因此,需要一个注释来帮助解释这一特殊情况。不管怎样,这是个好消息,很有趣!由于5.19左值到右值转换中的案例2引用了子对象,所以我不确定案例1是否应用于数组的成员。因此,这些案例之间有很多重叠。至于预处理器技巧…
#if
依赖于将标识符压缩到
0
来清理常量表达式。然后16.1/4适用,“生成的标记包含控制常量表达式,该表达式根据5.19的规则使用至少具有18.3中指定范围的算术进行计算。”仔细想想,UD后缀字符串不受
0
转换的影响!哦!是的,我同意。ud后缀派生为标识符,但作为预处理标记(预处理器操作的最小单元),它是用户定义的字符串文字标记的一部分。因此根据我的理解,
“foo”\ux
将永远不会转换为
“foo”0
。它保持为“foo”\u x,然后问题是后缀会发生什么:它被忽略了吗?这是一个错误吗?第三个(我不能接受,因为它超出了预处理器的范围)是-它会被查找吗?在我看来,根据目前的法律条文,它需要被查找。UD文本有一个由函数调用定义的值,5.19给出了关于允许哪些函数调用的规则。当然,如果它是模板的成员,这是不可能的。可能需要一份缺陷报告。第16条中的另一点假设字符串修饰只包含一个可能的前导
L
。字符串只是一个特例;允许预处理尚未转换为数值的数字。GCC和Clang拒绝FP值,即使没有标准禁止这些值。涵盖§5.19中的条件预处理问题。显然,该标准的工作草案已被修补,但修复被后来的更改覆盖。新的修正可能属于§16,因为当前的目的是拥有强大的常量表达式。
#if "\0\1\0\0\0\1"[ SOME_INTEGER_FLAG ]