この宣言:
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";
しかし、constexpr に const を追加すると、コンパイラは満足します。
char const constexpr *const s = "hello";
コンパイル:
g++ -g -Wall -Werror -std=c++17 test.cc -o test
./test
hello
これは私には直感的ではないようです。なぜ const が constexpr を修飾する必要があるのでしょうか? constexpr は const を意味しませんか? コンパイラ定数である場合、他の意味で定数ではないのはなぜですか? 何かが constexpr であっても、定数ではないように他の方法で変更される可能性はありますか?
最小限のゴッドボルトは次のとおりです。
アップデート:
StoryTeller の回答には、これを理解するための鍵があります。私は彼の回答を受け入れましたが、これを理解しようとしている他の誰かの役に立つかもしれないので、ここで詳しく説明します。const を操作するときは、const はその左側の項目に適用されると考えるのが普通です。つまり、次のようになります。
char a[] = "hello";
char * const s = a;
s[0] = 'H'; // OK
s = "there"; // Compiler error.
ここで、は、char * const s
ポインタ s が const である一方、それが逆参照する文字は変更可能であることを意味します。一方、
char const * s = "hello";
a[0] = 'H'; // Compiler error
s = "there"; // OK
この場合、char const * s
s が指す文字はポインタではなく const であることを意味します。
はい、const とポインターを扱ったことがある人なら、そのすべては理解できます。私が戸惑ったのは、constexpr も同じように動作すると想定していたことです。つまり、次のようになります。
char constexpr * const s = "hello";
これは、ポインタが const であり (実際そうです)、文字自体が const かつ constexpr であることを意味すると思いました。しかし、構文はそのようには機能しません。むしろ、この場合の constexpr は次のようになります。
- キャラクターには適用されませんが、むしろ...
s
ポインタである自分自身に適用され、そして...- したがって、ポインタの後の const は冗長です。
したがって、この場合、文字に対して const は宣言されていません。実際、constexpr を完全に削除すると、まったく同じエラーが発生します。
char * const s = "hello"; // Produces same error as char constexpr * const s = "hello";
ただし、これは機能します:
constexpr char const * s = "hello";
上記は私たちが求めているものであり、次のことを意味します。
- 文字はconst経由です
const
- そしてポインタ
s
はconstであり、コンパイル時の定数である。constexpr
ベストアンサー1
constexpr
意味しませんかconst
?
それは、物体宣言されていますs
。適用の結果はconstexpr
オブジェクトです
char *const s;
これはまだ、非 const オブジェクトを指すように宣言されています。アドレスのみが定数式である必要があります。つまり、static
ストレージ期間を持つオブジェクトを指す必要があります。
constexpr
何かが一定ではなく、他の方法で変化することは可能ですか?
いいえ。しかし、ここで変更が許可されているのは宣言されているオブジェクトではありませんconstexpr
。例えば
static char foo[] = "abc"; // Not a constant array
constexpr char * s = foo; // But the address is still a valid initializer.
有効な宣言のペアです。