17

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

constexpr char str[] = "hello, world";
constexpr char e = str[1];

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

constexpr char e = "hello, world"[1]; // error: literal is not constexpr

2.14.5/8 描述了字符串字面量的类型:

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

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

[constexpr允许左值到右值的转换] ...一个字面量类型的左值,它引用一个非易失性临时对象,其生命周期尚未结束,用常量表达式初始化

这特别奇怪,因为获取临时对象的左值通常是“作弊”。我想这条规则适用于引用类型的函数参数,例如

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

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

我在这里分裂了一些标准的头发......分析是否正确,这个功能是否有一些设计意图?

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

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

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

4

2 回答 2

6

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

您对预处理器中使用的评论看起来很有趣,但我不确定这是否可行。我第一次听说这件事。

于 2011-09-15T19:24:45.477 回答
1

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

于 2012-02-17T00:07:28.807 回答