transformed後にfilteredすると変換関数が2回呼ばれる
filtered dereferences underlying range elements twice
filteredの中で、イテレータの指す先が条件を満たすかをチェックするために間接参照し、その間接参照のたびにtransformedの変換関数が呼ばれるので、変換関数が多く呼ばれてしまうという問題。
#include <iostream> #include <boost/range/adaptor/transformed.hpp> #include <boost/range/adaptor/filtered.hpp> #include <boost/range/algorithm/for_each.hpp> int add(int x) { std::cout << "add function : " << x << std::endl; return x + 1; } bool pred(int x) { return true; } void disp(int x) { std::cout << x << std::endl; } int main() { using namespace boost::adaptors; const int ar[] = {1, 2, 3}; // 3要素なのでadd関数が3回呼ばれることを期待する boost::for_each(ar | transformed(add) | filtered(pred), disp); }
add function : 1 add function : 1 2 add function : 2 add function : 2 3 add function : 3 add function : 3 4
各要素に対して2回ずつadd関数が呼ばれてる。
これは仕組み上仕方がないので、メモ化しましょう。oven::memoizedです。
#include <iostream> #include <boost/range/adaptor/transformed.hpp> #include <boost/range/adaptor/filtered.hpp> #include <boost/range/algorithm/for_each.hpp> #include <pstade/oven/memoized.hpp> int add(int x) { std::cout << "add function : " << x << std::endl; return x + 1; } bool pred(int x) { return true; } void disp(int x) { std::cout << x << std::endl; } int main() { using namespace boost::adaptors; using pstade::oven::memoized; const int ar[] = {1, 2, 3}; // 3要素なのでadd関数が3回呼ばれることを期待する boost::for_each(ar | transformed(add) | memoized | filtered(pred), disp); }
add function : 1 2 add function : 2 3 add function : 3 4
すっきり。