const int よりも int const と書こう、という提案
……という提案を、試しにちょっとしてみます。
ポインタ型とconst
C++er の皆さん、次のコードを正しく説明できるでしょうか?
int hoge = 42; const int * p1 = &hoge; int const * p2 = &hoge; int * const p3 = &hoge;
もちろん答えはこうなります:
int hoge = 42; const int * p1 = &hoge; // p1の指示先を書き換える事はできないが、p1の指示先自体は変更可能 int const * p2 = &hoge; // p1と同じ int * const p3 = &hoge; // p3の指示先を書き換える事はできるが、p3の指示先自体は変更不能
つまり、const
が*
の前後どちらにあるかで意味が変わってくるわけですね。
この仕様は、知っている人にとっては不思議でも何でもないのですが、知らないと極めて不可解に見えるどころかソースコードをちゃんと日本語に直せません。困った。
と、そんなわけで今回の提案ですよ!
Oh! Japanese!!
試しに、こんなマクロを定義してみましょう。
#define の不変型 const #define へのポインタ型 *
これを使うと先程のコードは、
const int へのポインタ型 p1 = &hoge; // p1の指示先を書き換える事はできないが、p1の指示先自体は変更可能 int の不変型 へのポインタ型 p2 = &hoge; // p2の指示先を書き換える事はできないが、p2の指示先自体は変更可能 int へのポインタ型 の不変型 p3 = &hoge; // p3の指示先を書き換える事はできるが、p3の指示先自体は変更不能
となり、いずれの場合も*p
が書き換え可能かどうか、あるいはp
が変更可能かどうかが一目瞭然になりました。
同様に、
#define の最適化抑止型 volatile #define への参照型 & #define の一時オブジェクトへの参照型 &&
のようにもできます。これで「ポインタへの参照って*&
だっけ? それとも&*
だったっけ?」みたいな混乱からもオサラバ! 「ポインタ型への参照型」なんだから*
&
に決まってます!
なお、mutable
はconst
やvolatile
とは性質の異なるキーワードなので、必ず先頭に来なくてはなりません。
で、なんでint const
がいいの?
そんなわけで最初の提案に戻ります。
既に答えてしまったようなものですが、const
もvolatile
も*
も&
も&&
も、全て「既存の型に後ろから修飾する形で新しい型を作る」事ができるキーワードです。
が、const
やvolatile
は既存の型の直後に来る場合に限り、「既存の型の前から修飾する形で新しい型を作れ」ます。
もちろん、せいぜい「 const 整数へのポインタ」とか「整数への const ポインタ」とか言っていれらるうちはいいのですが、「 const 整数型への const ポインタのポインタの参照」と言われてconst int * const * &
とかさらっと出てくるのは相当の手馴れでしょう。
なのでここは、「整数型の不変型へのポインタ型の不変型へのポインタ型への参照型」と呼ぶ事にしましょう。それで、int const * const * &
と書きましょう……ほうら誰でも一発でわかる。
でも、本当は
正直、C++らしく、と思うとこんな風に書きたい:
pointer<add_const<int>::type>::type p1 = &hoge; // p1の指示先を書き換える事はできないが、p1の指示先自体は変更可能 add_const<pointer<int>::type>::type p3 = &hoge; // p3の指示先を書き換える事はできるが、p3の指示先自体は変更不能
でも面倒だから普通にconst
と*
使えばいいや。