字符串文字可以在常量表达式中下标吗?

Pot*_*ter 17 c++ string-literals constexpr c++11

这是有效的,因为一个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 literal not temporary
Run Code Online (Sandbox Code Playgroud)

对于它的价值,GCC 4.7接受get_1( "hello" ),但拒绝"hello"[1]因为"._0'的值在常量表达式中不可用"......但是作为案例标签或数组绑定"hello"[1] 可接受的.

我在这里拆分一些Standardese头发......分析是否正确,是否有一些设计意图?

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

#if "\0\1\0\0\0\1"[ SOME_INTEGER_FLAG ]
Run Code Online (Sandbox Code Playgroud)

这个结构对于C++ 11来说是新的.

Joh*_*itb 6

意图是这个工作和左值转换的左值有效的段落将被修改,注释表明引用字符串文字的子对象的左值是用常量表达式初始化的常量整数对象(在后C++ 11草案中被描述为允许的案例之一.

您对预处理器中的使用的评论看起来很有趣,但我不确定这是否有效.我第一次听到这个消息.

  • 我认为关键在于措辞已经支持这种解释,它只是不够明显而且存在疑虑; 因此有一个注释来帮助解释这个特殊的角落案例.无论如何,这是一个很棒的消息. (2认同)