チェックしてるのはそこじゃない

http://d.hatena.ne.jp/akiradeveloper/20091231/1262264357

すると、first_argument_typeとかがないよって怒られる。いやいや、怒り方違うだろと。binaryじゃないとダメだよって怒るのがふつう。

本当はそういう風にコンパイルエラー出してほしいのですが、その件についてはあとで。
元記事で求めている理想の bind2nd の姿を Java 風に書くと、こう。

template<typename Op extends binary_function, typename T>
binder2nd<Op> bind2nd(Op const & op, T const & right) { ... }

こうできれば、Op は binary_function を継承した型でないとコンパイルエラーにできそうです。で、これは C++ でできないのかというと、うまいことこの関数の型を書けばできるのですが、それはこの記事の本題ではないです。
なんで binary_function しか許さないようになっていないのかと言うと、その必要がないからです。要求する動作さえすれば binary_function 以外の型でも何も問題はありません。

struct int_adder {
    typedef int first_argument_type;
    typedef int second_argument_type;
    typedef int result_type;
    int operator()(int a, int b) const { return a + b; }
};

こういう型があったとして、bind2nd(int_adder(), 3)(5); と書いたら、これが 8 になりさえすればいいので、binary_function である必要はないのではないです。

つまり、transformはきちんとした型チェックを行っていない。これは、C++が境界を持った型パラメータを持っていないから起こること。RTTIを使えば、中で実行時に弾くことは出来るけど、実行時に弾くのじゃ型のありがたみがない。弾かないよりは弾いた方がいいかも知れないけど、めんどくさいし。

transform は関数テンプレートなので、件のコードの transform では、型を明記すると、 list::iterator transform(list::iterator begin, list::iterator end, back_insert_iterator > out, binder2nd > op) というような関数が生成されます。C++ の関数テンプレートでは、コンパイル時にテンプレート引数ごとに関数が生成されるので(型テンプレートでも同様)、型に対するチェックなどは、その生成された関数ごとにチェックされます。
で、冒頭のコンパイルエラーがおかしい、というのは、まぁ、だいたいはその通りなのですが、先に書いたように、binary_function 型である必要はなくて、本当は、first_argument_type, second_argument_type, result_type が定義されて、operator() 型ならなんでもいいので、そういうような要求をbinary_function_requireみたいな形で型とは違う制約として書いて、templateみたいなことを書けるようにしよう、という機能が次期 C++ 規格に提案されていたのですが、まとまらずにお蔵入りしました。残念。