为什么必须将 const 添加到 constexpr 中才能进行字符串文字声明?
Why does const have to be added to constexpr for a string literal declaration?
此声明:
char constexpr *const s = "hello";
失败并显示此错误:
g++ -g -Wall -Werror -std=c++17 test.cc -o test
test.cc:8:31: error: ISO C++11 does not allow conversion from string literal to 'char *const' [-Werror,-Wwritable-strings]
char constexpr *const s = "hello";
但是如果我将 const 添加到 constexpr 中,编译器很高兴:
char const constexpr *const s = "hello";
汇编:
g++ -g -Wall -Werror -std=c++17 test.cc -o test
./test
hello
这对我来说似乎不直观。为什么康斯特需要装饰康斯特普?constexpr 不意味着 const 吗?如果它是一个编译器常量,那么它怎么不是其他意义上的常量?有没有可能某些东西是 constexpr 但以其他方式发生变化,以至于不是恒定的?
这是一个最小的神螺栓:
https://godbolt.org/z/sSQMVa
更新:
StoryTeller的回答是理解这一点的关键。我已经接受了他的回答,但我会在这里扩展它,以防这对试图理解这一点的其他人有帮助。在与 const 交互时,我习惯于将 const 视为适用于其左侧的项目。因此:
char a[] = "hello";
char * const s = a;
s[0] = 'H'; // OK
s = "there"; // Compiler error.
在这里,char * const s
意味着指针 s 是常量,而它取消引用的字符是可修改的。另一方面:
char const * s = "hello";
a[0] = 'H'; // Compiler error
s = "there"; // OK
在这种情况下,char const * s
表示 s 指向的字符是 const,而不是指针。
好的,大多数使用过常量和指针的人都明白这一切。我被抛弃的地方是,我认为constexpr也会以这种方式工作。也就是说,鉴于此:
char constexpr * const s = "hello";
我认为这意味着指针是常量(确实如此(,而字符本身将是常量和常量。但是语法不是这样工作的。相反,在这种情况下,constexpr:
- 不适用于角色,而是...
- 适用于
s
本身,这是一个指针,并且... - 因此,指针后面的常量是多余的。
因此,在这种情况下,没有在字符上声明 const。事实上,如果我完全删除 constexpr,我会得到完全相同的错误:
char * const s = "hello"; // Produces same error as char constexpr * const s = "hello";
但是,这有效:
constexpr char const * s = "hello";
以上有我们想要的,这意味着:
- 字符通过
const
- 指针
s
是常量,并且通过constexpr
constexpr 不是意味着 const 吗?
在所声明的对象上,在您的情况下,它确实s
.应用constexpr
的结果是对象
char *const s;
它仍然声明为指向非常量对象。只有地址必须是常量表达式。这意味着它必须是具有静态存储持续时间的对象。
有没有可能某些东西是 constexpr 但以其他方式发生变化,以至于不是恒定的?
不。但话又说回来,这里不允许更改的不是被声明constexpr
的对象。例如
static char foo[] = "abc"; // Not a constant array
constexpr char * s = foo; // But the address is still a valid initializer.
是一对有效的声明。
const
适用于其左侧的事物,或者如果没有任何内容,则适用于其右侧。
在char *const s = "hello";
中,const
应用于*
,而不是char
,所以s
是一个指向非常量char
数据的常量指针。 但是,字符串文本是常量字符数据(在本例中,"hello"
是一个const char[6]
(。 您不能有一个指向实际指向常量数据的非常量数据的指针,这将允许常量数据可修改,如果某些东西实际尝试修改数据,这是未定义的行为。 这就是编译器错误所抱怨的。
因此,您需要一个指向常量字符数据的指针:
char const *const s = "hello";
或:
const char *const s = "hello";
constexpr
只是使s
变量在编译时可用于计算。
感谢StoryTeller的回答和Firebush的解释,这教会了我很多。
而把我带到这里的问题是关于array
const
,我做了一些简单的测试,比如Firebush。
关于数组,const
总是阻止修改特定维度而不是我认为可能对某些内容有所帮助的所有内容,所以我在这里发布测试代码和评论。
char* const strs1[] = {"uu", "vv"}; // protected 1st dimension
const char* strs2[] = {"ww", "xx"}; // protected 2nd dimension
char* strs3[] = {"yy", "zz"};
strs1[0] = "aa"; // error, try to modify 1st dimension
strs1[0][0] = 'a';
strs2[0] = "aa";
strs2[0][0] = 'a'; // error, try to modify 2nd dimension
strs1 = strs3; // error, try to modify 1st dimension
strs2 = strs3; // error, try to modify 2nd dimension
真相都在上面,最大的遗憾就是错过了几句话的简短有效的总结,让我们大家永远不要忘记const
的用法。
static constexpr auto NONE = "none";
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 如何使用字符串文字作为宏参数
- 有没有办法从非C/C++文件中读取C++原始字符串文字的内容
- 构造<int>具有 2 个字符串文字的向量
- 初始化或分配空字符串文字到指向 C 中的 char 的指针或指向 C++ 中 const char 的指针的原因是什么
- 方便地对C++中的所有字符串文字进行模糊处理
- 比较 std::string 和 C 样式字符串文字
- 如何从char16_t字符串文字中读取双精度?
- 如果我在块中编写字符串文字,是否会从数据部分复制整个字符串数据?
- C++ 不能在cout中使用向量和字符串文字
- 为什么必须将 const 添加到 constexpr 中才能进行字符串文字声明?
- C++:Unicode 字符串文字的可移植性
- 返回空字符串文字 VS. 返回空点 - 它们是一样的吗?
- 确保字符指针始终指向相同的字符串文字
- 如何按照 Google C++风格指南连接字符串文字?
- 通过 constexpr 中的 'const char *' glvalue 访问字符串文字的值会出错
- 字符串文字到 char 数组的转换如何在C++中实际工作
- 另一个字符串文字,UDL 迷宫
- strlen 是否针对字符串文字进行了优化?
- 用户定义的字符串文字为字符串null终止