C++テンプレートテクニックの感想とか
C++TT読み終わった。
現代的なC++で使われている技巧が一通り入ってて、なんというかこうtemplateの面白い部分ばっかり集めた収まりのいい本だなぁと思った。
個人的にはET解説ついでにラムダ式とかbindとか欲しかったとか思うけど、それやるとおそらく分量が素敵なことになる…
で、ちょっと気になったところとか思ったことをつらつらと。
p121〜p123 is_classメタ関数の説明
クラスの型特性ってのがよく分からない…クラスの特徴ってことでいいんだろうか。型特性は、C++ではtype traitsという英語の邦訳として使われていることが多いと思うので、それならtype traitsと同じように型の特性(constだの関数のシグニチャだの)というようなことを表わす用語として使われるべきで、ちょっと用語の濫用かも知れない…
クラスの型特性とはなんでしょうか?
「メンバを持っているか」ということを調べているということで解説が進んでいるけど、これまたよく分からない…よく分からないというか、自分の理解と違うので、なんかこうあやふやとしたような感じでしか読めない。
先ほどは「iterator 型を持っている」というチェックをtypename C::iteratorと書きましたが、「メンバを持っている」というのは同じように「C::*」と書くことができます。(snip)int型や、メンバ変数ポインタといったものは重要ではないのです。
is_classは、Cを実際に何かの型に置き換えた際、「Cのメンバへのポインタ型」がC++の型として問題ないかどうか、ということをもってクラスかどうか判断しようというもので、それを「メンバを持っているか」と表現すると何かこう違和感ががが。あまりスマートな言い方じゃないけど、「メンバに関する何かを使うことができるか」ということを調べる手段として、「メンバへのポインタの型が使えるか」を調べているとか、そんな感じの意味で捉えればいいのだろうか…というかまぁそれは私が解釈していることそのままなんだけど。
p201 friend非メンバ関数のインライン定義の説明
これはあたかも非メンバ関数として定義したんじゃなくて、実際に非メンバ関数だと思う。C++03の規格が手元にないので、n2800で言うと11.4.6。
operator==をfriendとしてクラススコープ内でインライン定義することで、operator==をあたかも非メンバ関数として定義したかのように振る舞わせることができます。
あと、この例ではhogeへの自動変換が存在しないので特に問題はないけど、operator==をメンバ関数として書くと、
struct piyo {}; template<typename T> struct op_not_equal { friend bool operator!=(T, T) { ... } }; struct hoge : public op_not_equal<hoge> { bool operator==(hoge) { ... } hoge() {} hoge(piyo) {} }; void f() { hoge() == hoge(); // ok hoge() == piyo(); // ok piyo() == hoge(); // ng piyo() == piyo(); // ng piyo() != piyo(); // 規格ではokのはず!(後述) }
hogeとpiyoの==での比較は不自由なのに、!=はいかなる組み合わせ(上の例では一つしか書いてないけど)でも比較できてしまうというアンバランスな感じになってしまう(このへんはEffective C++のどこかに書いてありまする)。けどまぁ本題とは一切関係ないのですが。
p204〜p205
http://d.hatena.ne.jp/Cryolite/20040608#p1 にあるように、これはコンパイラによる独自の挙動として見えなくした結果、呼び出せなくなっているのであって規格通りの動作ではないはずだけど、この場で重要なのは多分「frined宣言で定義した関数は、メジャーなコンパイラでは、ADL経由でしか見えない」という事実なので、それじゃ結局私は何が言いたかったのか…あぁ、なんかその旨書いといたほうがいいんじゃないかなぁとか思ったけど、細かいこと気にする人以外にとってはどうでもいいことなのでやっぱりいいか。
Barton-Nackman trickでは、クラススコープ内でfriend関数を定義します。ところが、これを使用するとクラススコープ内のfriend関数を直接呼び出すことはできないのです。
で、その一つ前のpiyo() != piyo()の話に戻って、operator!=がhogeのADL経由でしか見えなくなっているので、piyoからだと見つからなくてコンパイルエラーとなるけど、規格的には通らなければいけないと。当然だけどoperator!=(hoge, hoge)がfriendでクラス内で定義とかじゃなく、普通にクラス外で非メンバ関数として定義されていればpiyo() != piyo()も通る。
p236
plusとかmultiplyのメンバ関数の型がfloat決め打ちなのが気になる…これをまじめにやろうとするととても面倒なのは知ってるけど。できればその旨を一言添えておくべきだと思ったけど、これもとりあえずは触れないということなんだろうか。
p238
たまにはoperator->*のことも思いだしてあげてくだしあ><
ここでは、これらの条件内でも使用頻度が低い「operator|」を使用します