constexpr const char * vs constexpr const char[]

20

"第一次尝试"编译不通过,而第二次可以。为什么?有什么区别?

第一次尝试:

#include <iostream>

int main()
{
    constexpr const char text2[] = "hello";
    constexpr const char * b = &text2[4];  // error: '& text2[4]' is not a constant expression
    std::cout << b << std::endl;
}

第二次尝试:

#include <iostream>
int main()
{
constexpr const char * text1 = "hello";
constexpr const char * a = &text1[4];
std::cout << a << std::endl;

return 0;
}

我使用(g++版本4.9.2)进行编译

g++ -std=c++11 -o main *.cpp

这会导致以下错误

main.cpp: In function 'int main()':
main.cpp:7:40: error: '& text2[4]' is not a constant expression constexpr const char * b = &text2[4];  // error: '& text2[4]' is not a constant expression  

1
我喜欢你在第一次尝试中将变量命名为text2,在第二次尝试中将其命名为test1。 - shargors
1个回答

27
从C++11标准草案第5.19节[expr.const]可以看出,地址常量表达式是一个prvalue核心常量表达式,其指针类型的值求值为具有静态存储期的对象的地址,函数的地址,空指针值或std :: nullptr_t类型的prvalue核心常量表达式。(强调是我的)
在您的第一种情况中,尽管"hello"是具有静态存储期的字符串文字,但它被复制到没有静态存储期的数组text2中。
而在您的第二种情况中,text1是指向具有静态存储期的字符串字面值的指针。

将您的第一个示例更改为使text2静态(查看实时演示):

constexpr char static text2[] = "hello";
               ^^^^^^

我们不再收到错误信息。
从第2.14.5节[lex.string]中,我们可以看出字符串字面值具有静态存储期:

普通字符串字面值和UTF-8字符串字面值也被称为窄字符串字面值。 窄字符串字面值具有类型“数组n const char”,其中n是如下定义的字符串的大小,并且具有静态存储期(3.7)。


const 会让 constexpr 变得更加常量化吗? - edmz
@black 不,它们对 text2不同的作用,对于指针来说是必需的,但对于 text2 来说并不需要。 - Shafik Yaghmour
3
需要思考一下,最好将其写出来:在text2的情况下,数组从字符串字面量中初始化,但是该数组是字符串的每个实例的副本,因此获取第五个元素的地址会指向每个实例中的不同位置,这不是一个常量表达式。在text1的情况下,字符串字面量被放置在静态空间,而text1被设置为类的每个实例中相同的地址,因此获取第五个元素的地址会指向每个实例中相同的位置,这是一个常量表达式。 - Blair Houghton
@BlairHoughton 这是一个很好的观点,我后来意识到指出这一点可能会有帮助。感谢您的评论。 - Shafik Yaghmour

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接