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非メンバ関数のインライン定義の説明


operator==をfriendとしてクラススコープ内でインライン定義することで、operator==をあたかも非メンバ関数として定義したかのように振る舞わせることができます。
これはあたかも非メンバ関数として定義したんじゃなくて、実際に非メンバ関数だと思う。C++03の規格が手元にないので、n2800で言うと11.4.6。
あと、この例では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


Barton-Nackman trickでは、クラススコープ内でfriend関数を定義します。ところが、これを使用するとクラススコープ内のfriend関数を直接呼び出すことはできないのです。
http://d.hatena.ne.jp/Cryolite/20040608#p1 にあるように、これはコンパイラによる独自の挙動として見えなくした結果、呼び出せなくなっているのであって規格通りの動作ではないはずだけど、この場で重要なのは多分「frined宣言で定義した関数は、メジャーなコンパイラでは、ADL経由でしか見えない」という事実なので、それじゃ結局私は何が言いたかったのか…あぁ、なんかその旨書いといたほうがいいんじゃないかなぁとか思ったけど、細かいこと気にする人以外にとってはどうでもいいことなのでやっぱりいいか。
で、その一つ前のpiyo() != piyo()の話に戻って、operator!=がhogeのADL経由でしか見えなくなっているので、piyoからだと見つからなくてコンパイルエラーとなるけど、規格的には通らなければいけないと。当然だけどoperator!=(hoge, hoge)がfriendでクラス内で定義とかじゃなく、普通にクラス外で非メンバ関数として定義されていればpiyo() != piyo()も通る。

p236

plusとかmultiplyのメンバ関数の型がfloat決め打ちなのが気になる…これをまじめにやろうとするととても面倒なのは知ってるけど。できればその旨を一言添えておくべきだと思ったけど、これもとりあえずは触れないということなんだろうか。

p238


ここでは、これらの条件内でも使用頻度が低い「operator|」を使用します
たまにはoperator->*のことも思いだしてあげてくだしあ><

p303


template<typename T> using Vec = Vec_<T>::type;
=の後ろにtypename抜けてる

追記:
id:xyuyuxさんからいくつかtypoの指摘をいただいたので修正しました。ありがとうございます。