2006年06月23日
_ C++いろいろ
以下の OCaml の コードを
open List let f lst = let even n = n mod 2 = 0 in let pow2 n = n * n in fold_left (+) 0 (map pow2 (filter even lst))
C++ で表現しようとします。
で、コードその1。
int f(std::vector<int>& v) { int sum = 0; for(int i = 0; i < v.size(); ++i){ if(v[i] % 2 == 0) sum += v[i] * v[i]; } return sum; }
コードその2。次にイテレータでちょっと抽象化。
template<typename Iter> int f(Iter first, Inter last) { int sum = 0; for(Iter it = first; it != last; it++){ if(*it % 2 == 0) sum += (*it)*(*it); } return sum; }
これだと最初のOCamlのコードとは1対1対応していません。 というわけで stl の algorithm を使ってみます。コードその3
#include <iostream> #include <vector> #include <algorithm> #include <numeric> using namespace std; class Odd{ public: bool operator()(int n){ return (n%2==1); } }; class Pow2{ public: int operator()(int n){ return n*n; } }; template<typename Iter> int f(Iter first, Iter last) { vector<int> v1, v2; remove_copy_if(first, last, back_insert_iterator<vector<int> >(v1), Odd()); transform(v1.begin(), v1.end(), back_insert_iterator<vector<int> >(v2), Pow2()); return accumulate(v2.begin(), v2.end(), 0); }
コードその4。関数オブジェクトのクラスが邪魔なので boost::lambda を使います。
#include <iostream> #include <vector> #include <algorithm> #include <numeric> #include <boost/function.hpp> #include <boost/lambda/lambda.hpp> using namespace std; template<typename Iter> int f(Iter first, Iter last) { using namespace boost::lambda boost::function<bool (int)> odd = (_1%2!=0); boost::function<int (int)> pow2 = (_1 * _1); vector<int> v1, v2; remove_copy_if(first, last, back_insert_iterator<vector<int> >(v1), odd); transform(v1.begin(), v1.end(), back_insert_iterator<vector<int> >(v2), pow2); return accumulate(v2.begin(), v2.end(), 0); }
コードその5。中間データ用の vector は別に必要ないはず、ということで iterator_adaptor を使ってみます。
#include <algorithm> #include <numeric> #include <functional> #include <boost/functional.hpp> #include <boost/function.hpp> #include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/filter_iterator.hpp> #include <boost/lambda/lambda.hpp> using namespace std; template<typename Iter> int f(Iter first, Iter last) { using namespace boost::lambda; using boost::make_transform_iterator; using boost::make_filter_iterator; boost::function<bool (int)> is_even = (_1%2==0); boost::function<int (int)> pow2 = (_1 * _1); return accumulate(make_transform_iterator(make_filter_iterator(is_even,first, last), pow2), make_transform_iterator(make_filter_iterator(is_even,last, last), pow2), 0); }
以上。<URL:http://www.kmonos.net/alang/boost/> や <URL:http://shinh.skr.jp/boost/iterator_adaptors.html> を参考にして書きました。iterator_adaptorを使いたかったというだけだという気もします。
個人的にはコードその2くらいにしておくのが良いのではと思います。