std::pair の要素に名前を付けてアクセスする


2010年 11月 26日

最初にお断りしておく。
本記事は恐らく実際に使用することは滅多にないと思われる類の話である。
要は自己満足系の何かで、使うにしても本当に必要なのかどうかちゃんと考えるべきだ。

でも単純に楽しいんだよね…。

さて、STLのstd::pairは、普通要素にアクセスするときは first、second でアクセスする。
しかしこれ、実に味気ない名前であって、汎用性があるといえば聞こえはいいが、
どっちに何が入っているか把握していないといけない。
そんなわけで、名前がつけられたらいいなあ、なんて思うワケだ。

そんなところに登場するのが、メンバへのポインタである。
細かいことを色々説明するのが面倒なので、
ざっくりサンプルコードを見て欲しい。こんな感じになる。

ポインタ定義のところとか読めたもんじゃないよな。これだからC++は。
typedefを展開すると更に楽しいことになるが、あまり意味はないのでやめておく。

そしてもちろん、出力はこうだ。

Sample:100
Sample2:120

…むう。

.* とか ->* とか、実に見慣れない記号の羅列だが、れっきとしたC++の演算子である…。

私は正式な呼び方は存じないのであるが、
直接メンバポインタ参照演算子(.*)とか、
間接メンバポインタ参照演算子(->*)とかいう感じだろうか。
実にけったいなことである。

更に、いずれの演算子も直接メンバ参照演算子(.)よりも優先度が低いせいで、
例のc_str()呼び出しの前の括弧を省略することができない。
ぱっと見では別に同じ優先順位で良かったんじゃないかとは思うのだが、
如何せんC++のことなので多分やんごとなき事情があったのだろう。

で、元々の話は名前を付けるとかそういう話だった気がするのだが、
さすがにこれが自己満足に過ぎないことは私も分かっている。
上記例の場合には明らかに次の構造体を定義すべきだ:

struct sample_t {
    std::string name;
    int         point;
};

とはいえ、std::mapの要素がstd::pairなのでその辺で…、使い道が…、
…。ないよなあ。

使い道はともかく、ちょっと気になるのが name 及び point ポインタ変数の具体的な中身だ。
こいつらは、メンバへのポインタという名前の通り、構造体先頭からのオフセットが入っている。
強引に表示してみればわかるが、例えば手元の環境では name は 0、point は 4 だった。
ともあれ、ポインタであることに変わりはない。

実に使い道の薄そうな話ではあったが、所詮ただのポインタであり、
ポインタを用いて構造体(=クラス)のメンバを参照できるという事実は、
名前付けに限らなけばいくらか使い道は考えられるので、
そんなものもあるんだ、くらいには思っておいても良いかもしれない。
データメンバへのポインタはともかく、
メンバ関数ポインタなら見たことがある人も居るのではないだろうか。