简体   繁体   English

为什么必须将 const 添加到 constexpr 才能进行字符串文字声明?

[英]Why does const have to be added to constexpr for a string literal declaration?

This declaration:本声明:

char constexpr *const s = "hello";

Fails with this error:失败并出现此错误:

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";

But if I add const to constexpr, the compiler is happy:但是如果我将 const 添加到 constexpr,编译器会很高兴:

char const constexpr *const s = "hello";

Compilation:汇编:

g++ -g -Wall -Werror -std=c++17 test.cc -o test
./test
hello

This seems unintuitive to me.这对我来说似乎不直观。 Why does const need to decorate constexpr?为什么const需要修饰constexpr? Doesn't constexpr imply const? constexpr 不意味着 const 吗? If it's a compiler constant, how is it not a constant in some other sense?如果它是编译器常量,那么它在其他意义上怎么不是常量? Is it possible for something to be constexpr but change in some other way such that is not constant?是否有可能某些东西是 constexpr 但以其他方式改变而不是恒定的?

Here's a minimal godbolt:这是一个最小的上帝螺栓:

https://godbolt.org/z/sSQMVa https://godbolt.org/z/sSQMVa


Update:更新:

StoryTeller's answer has the key to understanding this. StoryTeller 的回答是理解这一点的关键。 I've accepted his answer, but I'll expand on it here in case that's helpful for someone else trying to understand this.我已经接受了他的回答,但我会在这里扩展它,以防其他人试图理解这一点。 When interacting with const, I'm used to thinking of const as applying to the item on the left of it.在与 const 交互时,我习惯于将 const 视为应用于其左侧的项目。 Thus:因此:

char a[] = "hello";
char * const s = a;
s[0] = 'H'; // OK
s = "there"; // Compiler error.

Here, char * const s means that the pointer, s, is const while the characters it dereferences to are modifiable.在这里, char * const s意味着指针 s 是 const 而它取消引用的字符是可修改的。 On the other hand:另一方面:

char const * s = "hello";
a[0] = 'H'; // Compiler error
s = "there"; // OK

In this case, char const * s means that the characters that s points to are const, not the pointer.在这种情况下, char const * s表示 s 指向的字符是 const,而不是指针。

OK, most people who have worked with const and pointers understand all that.好的,大多数使用过 const 和指针的人都明白这一切。 Where I got thrown off is that I assumed that constexpr would work this way as well.我被抛弃的地方是我认为 constexpr 也会以这种方式工作。 That is, given this:也就是说,鉴于此:

char constexpr * const s = "hello";

I thought that would mean that the pointer is const (it is) and that the characters themselves would be const and constexpr.我认为这意味着指针是 const(它是)并且字符本身是 const 和 constexpr。 But the syntax doesn't work that way.但是语法不是这样工作的。 Rather, the constexpr in this case:相反,这种情况下的 constexpr :

  • Does not apply to the characters, but rather...不适用于角色,而是...
  • applies to s itself, which is a pointer, and...适用于s本身,它是一个指针,并且...
  • therefore is redundant with the const after the pointer.因此与指针后的 const 是多余的。

Thus, in this case, there is no const being declared on the characters.因此,在这种情况下,没有在字符上声明 const。 Indeed, if I remove the constexpr entirely I get the exact same error:事实上,如果我完全删除 constexpr 我会得到完全相同的错误:

char * const s = "hello"; // Produces same error as char constexpr * const s = "hello";

This, however, works:但是,这有效:

constexpr char const * s = "hello";

The above has what we want and it means:以上有我们想要的,这意味着:

  • The characters are const via const字符是 const 通过const
  • And the pointer s is const and a compile time constant via constexpr并且指针s是 const 和一个通过constexpr编译的时间常数

Doesn't constexpr imply const? constexpr 不意味着 const 吗?

It does, on the object being declared, in your case s .确实如此,在您的情况下,在声明的objects The result of applying constexpr is the object应用constexpr的结果是 object

char *const s;

It's still declared to point at a non-const object.它仍然声明指向一个非常量 object。 Only the address has to be a constant expression.只有地址必须是常量表达式。 Which means it must be to an object with static storage duration.这意味着它必须是具有 static 存储持续时间的 object。

Is it possible for something to be constexpr but change in some other way such that is not constant?是否有可能某些东西是 constexpr 但以其他方式改变而不是恒定的?

No. But then again, it's not the object being declared constexpr that is allowed to change here.不,但话又说回来,这里不允许更改被声明为constexpr的 object。 For instance例如

static char foo[] = "abc"; // Not a constant array
constexpr  char * s  = foo; // But the address is still a valid initializer.

Is a valid pair of declarations.是一对有效的声明。

const applies to the thing on its left, or if nothing is there then to its right. const适用于它左边的东西,或者如果什么都没有,那么它的右边。

In char *const s = "hello";char *const s = "hello"; , the const is applied to the * , not to the char , so s is a const pointer to non-const char data. const应用于* ,而不是char ,因此s是指向非 const char数据的 const 指针。 However, a string literal is const char data (in this case, "hello" is a const char[6] ).但是,字符串文字是 const char 数据(在这种情况下, "hello"const char[6] )。 You can't have a pointer to non-const data that is actually pointing at const data, that would allow the const data to be modifiable, which is undefined behavior if something actually tried to modify the data.您不能拥有指向实际指向 const 数据的非 const 数据的指针,这将允许 const 数据可修改,如果实际尝试修改数据,这是未定义的行为。 That is what the compiler error is complaining about.这就是编译器错误所抱怨的。

So, you need a pointer to const char data instead:因此,您需要一个指向 const char 数据的指针:

char const *const s = "hello";

Or:或者:

const char *const s = "hello";

The constexpr just makes the s variable available for evaluation at compile-time. constexpr只是使s变量可用于在编译时进行评估。

Thanks for StoryTeller's answer and Firebush's explanation which teach me a lot.感谢 StoryTeller 的回答和 Firebush 的解释,它们教会了我很多东西。

And the problem lead me here is about const with array , I have done some simple test like Firebush.导致我的问题是关于constarray ,我做了一些简单的测试,比如 Firebush。

Regard for array, const always prevent to modify specific dimension instead of all content which I think maybe help for some one, so I post test code and comments here.关于数组, 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

The truth is all above, the biggest regret is miss a short and effective summary in several words to make all of us never forget the usage of const .道理都在上面,最大的遗憾是错过了一个简短而有效的几句话总结,让大家永远不会忘记const的用法。

static constexpr auto NONE = "none";

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM