質問: ``` const int func(int a){...}; // 1 int const func(int a){...}; // 2 int func(int a) volatile {...}; // 3 ``` 1番と2番は全く同じ意味ですよね? **これは返り値がconstになる**・・・??という意味ですか?? 3番めはメンバ関数にできることですが、これは・・・**この関数が呼び出されている間だけメンバ変数を最適化抑止するという意味ですか??** 1番と2番については紛らわしくなりそうです。 例えば ``` constexpr int func(){...}; ``` constexpr関数になりますが・・・これだと変数を修飾しているように見えませんか?? 以下のほうが関数を修飾しているように見えません?? ``` int constexpr func(){...}; ``` 逆に、以下のようにすると、関数全体を最適化抑止しているのかな??という風に見えませんか?? ``` volatile int func(){...}; ``` これも返り値が最適化抑止ということですよね?? なんか紛らわしいですね・・・ inlineにも同じことが言えそうなんですが・・・ noexceptもわかりにくいです。 ``` int noexcept func(){...}; // ERROR!!! 前には書けない。 ``` noexceptの場合は、上記はダメでした。 お尻のほうに書かないといけないようです。 例外を送出しない関数なら前に書いたほうが良いような気がするんですが・・・ リンク内容) mutable const volatile inline など細かく分類されているようです。 修飾子と指定子の違いがよく分かりません。 記述する場所もイマイチはっきりしていません。 先頭に記述する場合と後ろに記述する場合の違いがよくわからないです。 **修飾したい対象のものの直前**と統一すれば分かりやすいと考えています。 しかし実際にはそうなっていないですよね。 どなたか教えてください。 わかりにくい。 予約語によって記述箇所が異なるので、全パターン覚えないといけないんですかね? 環境は Linux 64bit gcc です。
回答: こんにちは。 constは型を修飾します。int const、const intはどちらも変更不可なint型の意味ですね。 メンバ関数の後ろに記述するconstは判りにくいですね。 メンバ関数は隠しパラメータとして`*this`を持っています。その`*this`の型を修飾しています。要するにthisの指す先をconst(変更不可)として扱います。 volatileはconstと同じく型を修飾します。メンバ関数の後ろに書いているのを見たことはないですが、同じことの筈です。thisの指す先をvolatileとして扱う筈です。この場合、volatileが有る時と無い時で何が変わるのか私は良く分かりません。何も変わらないような気もします。 その使い方のconstexprは関数を修飾します。陶芸家の中3女子の方の解説が詳しいです。 constexprの読み方はチュウサンジョシと言われる程です。 noexceptも関数を修飾します。これは覚えましょう。 > > 予約語によって記述箇所が異なるので、全パターン覚えないといけないんですかね? > > > そういうことですね。数もたかがしれていますし、直ぐ慣れますよ。 【蛇足ですが】 個人的にはnoexceptはあまり使わない方がよいように思います。例外が飛んでくるのに間違って付けると例外が投げられた時、エラー情報が消えてしまうので。 コンパイラはnoexceptな関数が直接例外を投げないことしかチェックしてくれません。その関数が呼び出している関数が投げないことはチェックしてくれないのです。 noexcept関数内でtry-catchして例外情報を残すか、小さな関数でパッと見て例外が投げられないことが明確な場合のみしか付けるべきではないように思います。 ``` #include void bar() { throw 12345; } void foo() noexcept // ←このnoexceptをなくせば例外の内容が表示される { bar(); } int main() { try { foo(); } catch(int e) { std::cout << "catch(" << e << ")\n"; } } ``` wandbox