Constexpr関数にはconst指定子がありません

警告したいだけです。C++ 14はconstexpr



関数の1つの側面でC ++ 11と後方互換性がありません。



C ++ 11では、 constexpr



メンバー関数を定義すると、暗黙的にconst



指定子が取得されます。

 // C++11 struct NonNegative { int i; constexpr int const& get() /*const*/ { return i; } int& get() { return i; } };
      
      





get



関数の最初の宣言は、明示的に指定しなくてもconst



指定子を受け取ります。 したがって、これら2つの関数は、 const



バージョンと非const



バージョンです。



C ++ 14では、これは当てはまりません。両方の宣言が、異なる戻り値を持つメンバー関数の同じ非const



バージョンを決定するため、コンパイルエラーが発生します。 constexpr



関数の使用を既に開始していて、暗黙的なconst



指定子を希望している場合は、C ++ 14コンパイラーに切り替えることを決定した場合にコードがコンパイルし続けるように、明示的に追加することをお勧めします。



暗黙のconst



何が問題になっていますか?



次のようにタイプを使用しようとすると、問題が始まります。

 // C++11 constexpr int i = NonNegative{2}.get(); // ERROR
      
      





(やや珍しい)C ++ルールによれば、一時オブジェクトのメンバー関数を選択するときは、 const



バージョンよりもconst



バージョンの方が適しています。 非const



メンバー関数get



constexpr



get



ないため、 constexpr



変数の初期化には使用できず、コンパイル段階でエラーが発生します。 この関数をconstexpr



にすることはできませんconstexpr



が自動的に追加されるためです...



最適な関数を選択するためのルールは、一時オブジェクトに最適な非メンバー関数を選択する方法に少し反するため、珍しいと言いました。 この場合、非const



バージョンへのリンクのconst



左辺値を優先します。

 // C++11 constexpr int const& get(NonNegative const& n) { return ni; } constexpr int& get(NonNegative& n) { return ni; } NonNegative N = readValue(); constexpr int * P = &get(N); int main() { *P = 1; }
      
      





何が起こるか見てください:グローバル変数N



定数でN



ません。 したがって、2番目の非const



オーバーロード関数は、ポインターP



初期化時に呼び出されるように選択されますP



しかし、非const



関数にはconstexpr



がまだありconstexpr



! そして、すべてのルール「 constexpr



const



意味する」は、非静的メンバー関数の暗黙のthis



引数にのみ適用されるためです。 constexpr



関数は、非const



オブジェクトへの参照を取得し、非const



サブオブジェクトへのリンクを返すことができます。 ここには問題はありません。グローバルオブジェクトのアドレスは一定であり、コンパイル時に既知です。 ただし、アドレスP



の値は一定でP



なく、後で変更できます。



前の例がやや難解に見える場合は、次のより現実的な例を検討してください。

 // C++11 constexpr NonNegative* address(NonNegative& n) { return &n; } NonNegative n{0}; // non-const constexpr NonNegative* p = address(n);
      
      





ここではすべて正常に機能しますが、 address



をメンバー関数にしようとすると、機能しなくなります。

 // C++11 struct NonNegative { // ... constexpr NonNegative* maddress() { return this; } // ERROR }; NonNegative n{0}; // non-const constexpr NonNegative* p = n.maddress();
      
      





これは、 maddress



const



指定maddress



暗黙的に定義され、 this



NonNegative const*



型であり、 NonNegative*



変換できないためです。



これはメンバー関数自体がconst



であるのではなく、関数に対する暗黙のthis



)引数であることに注意してください。 メンバー関数宣言は、次のように擬似コードで書き直すことができます。

 // PSEUDO CODE struct NonNegative { // ... constexpr NonNegative* maddress(NonNegative const& (*this)); };
      
      





そして、この暗黙的な関数引数は、他の関数引数とは異なり、(時には望ましくない) const



修飾子を取得します。



この非対称性はC ++ 14で削除されます。 暗黙的な引数( this



)のconst



指定子が必要な場合は、自分で追加する必要があります。 次のコードは、C ++ 14で有効です。

 // C++14 struct NonNegative { int i; constexpr int const& get() const { return i; } constexpr int& get() { return i; } };
      
      






All Articles