2015-12-02-01-STL書籍の掲載コードをCL-STLで書いてみよう-19 - project-enigma

2015-12-02-01-STL書籍の掲載コードをCL-STLで書いてみよう-19

>> Site top >> weblog >> 月別アーカイブ >> 2015年12月のlog >> 2015-12-02-01-STL書籍の掲載コードをCL-STLで書いてみよう-19

最終更新日付:2015/12/02 08:21:43


STL書籍の掲載コードをCL-STLで書いてみよう-19

2015 年 12 月 02 日

今回は、Effective STL の「第40項:ファンクタクラスを変換可能にしよう」を。なんていうか、まぁあまり面白くない感じになってしまったので血圧低めで流していこう。

Widget のポインタを格納したコンテナと、Widget が面白いかどうかを判定する述語関数があるとして、

list<Widget*> widgetPtrs;
bool isInteresting( const Widget* pw );

 

シーケンス内で最初の「面白いやつ」を探すには以下のようにする。教科書通りだ。

list<Widget*>::iterator i = find_if( widgetPtrs.begin(),
                                     widgetPtrs.end(), isInteresting );
if( i != widgetPtrs.end() ) {
    //...
}

 

で、問題は次。最初の「面白くないやつ」を探そうとして以下のようにするとコンパイルに通らないよ、という話だ。これが今回の主題だ。

list<Widget*>::iterator i = find_if( widgetPtrs.begin(),
                                     widgetPtrs.end(), not1( isInteresting ) );

 

理由ははっきりしている。isInteresting が関数だからだ。not1unary_negate を作成するためのヘルパ関数だが、パラメータが STL の規約に沿った typedef を備えたファンクタクラスでない場合、必要な型情報を引っ張ってくることができない。これが「ファンクタクラスが変換可能か否か」という問題だ。ちなみに、関数を直接「変換可能」にすることはできないから、ひとまずは ptr_fun を使う。以下のように。

list<Widget*>::iterator i = find_if( widgetPtrs.begin(),
                                     widgetPtrs.end(), not( ptr_fun( isInteresting ) ) );
if( i != widgetPtrs.end() ) {
    //...
}

 

書籍ではこの後もいくつかコードが出てくるが、ここでは取りあげない。というのも、CL-STL ではこれらのことが問題にならないからだ。どういうことか、以下に示そう。まず、簡単のために整数を扱うとして、「10以上で7の倍数なら面白い」とみなす関数 is-interesting を用意する。深い意味はないよ。

(defun is-interesting (v)
  (and (<= 10 v)
       (zerop (mod v 7))))

 

で、これを普通に使った様子が以下。何の問題もない。そりゃそうだよね。

(let ((c (new stl:list #{10 11 12 13 14 15})))
  (let ((i (stl:find-if (stl:begin c) (stl:end c) #'is-interesting)))
    (if (_/= i (stl:end c))
        (_* i)
        :not-found)))

;=> 14

 

では、「面白くない最初の整数」を検索するために以下のようにする。C++ の例では、ptr_fun を使わなければコンパイルに通らなかったものだ。しかし CL-STL では問題なく実行される。

(let ((c (new stl:list #{14 21 28 34 42})))
  (let ((i (stl:find-if (stl:begin c)
                        (stl:end   c) (stl:not1 #'is-interesting))))
    (if (_/= i (stl:end c))
        (_* i)
        :not-found)))

;=> 34

 

‥‥‥まぁ、当然と言えば当然だ。静的な型チェックをしていないのだから。そういうわけなので、CL-STL では ptr_fun のようなアダプタを使わなくても関数を not1 に渡すことができるのだ。

こうなると、CL-STL では「ファンクタでなく関数」を使う方になおのこと誘導される。Effective STL の別の項ではパフォーマンスの観点から「関数よりもファンクタ」をお勧めしているが、CL-STL ではその利点もない。いよいよファンクタを使う積極的な理由が見当らないのだ。嗚呼。

まぁ、それはそれでいいのかもしれない。CL-STL は Common Lisp で STL を使いたいと思ったから作り始めたものであって、Common Lisp を C++ にしようという試みではないのだ。言語が違えば、同じ問題に対する最適解も違うというものだろう。

 

このシリーズのこれまでのエントリ

 

コメント

このページにコメントする

 

このページのタグ

Page tag : STLとその移植

Page tag : Common Lisp

 

 


Copyright(C) 2005-2017 project-enigma.
Generated by CL-PREFAB.