transform_if?
と、いうものを Twitter で見かけたのでちょっと書いてみました。
transform_if の挙動としては、
- cond == true の要素のみを関数に適用させる(range のサイズはそのまま)
- 要素をフィルタリングしてから関数に適用させる(filter + transform)
と、いう処理が考えられますが、ちょっと違うアプローチを考えて見ました。
[ソース]
#define BOOST_RESULT_OF_USE_DECLTYPE #include <iostream> #include <pstade/oven/transformed.hpp> #include <pstade/oven/filtered.hpp> #include <pstade/oven/counting.hpp> #include <pstade/oven/identities.hpp> #include <pstade/oven/io.hpp> #include <pstade/result_of_lambda.hpp> #include <boost/lambda/lambda.hpp> #include <boost/optional.hpp> struct boost_optional_add_star{ template<typename T> struct result; template<typename F, typename T> struct result<F(boost::optional<T>)>{ typedef T type; }; template<typename F, typename T> struct result<F(T)>{ typedef T type; }; template<typename T> typename result<boost_optional_add_star(boost::optional<T>)>::type operator ()(boost::optional<T> const& t) const{ return *t; } template<typename T> typename result<boost_optional_add_star(T)>::type operator ()(T const& t) const{ return t; } }; template<typename Range, typename Func> auto maybe_transform(Range const range, Func f) ->decltype(range |pstade::oven::transformed(f) |pstade::oven::filtered(boost::lambda::_1) |pstade::oven::transformed(boost_optional_add_star()) ){ return range |pstade::oven::transformed(f) |pstade::oven::filtered(boost::lambda::_1) |pstade::oven::transformed(boost_optional_add_star()); } int main(){ using pstade::oven::counting; using pstade::oven::identities; std::cout << ( maybe_transform(counting(0, 10), [](int n){ return n % 2 == 0 ? boost::optional<int>(n + n) : boost::none; }) |identities) << std::endl; std::cout << ( maybe_transform(counting(0, 10), [](int n){ return n % 2 != 0 ? n * n : n; }) |identities) << std::endl; // 0 は false なのでフィルタリングされる std::cout << ( maybe_transform(counting(0, 10), [](int n){ return n % 2 == 0 ? n + n : 0; }) |identities) << std::endl; return 0; }
[出力]
{0,4,8,12,16} {1,2,9,4,25,6,49,8,81} {4,8,12,16}
Boost.Optional を関数の戻り値型にすることで、関数内で要素のフィルタリングの有無を決定します。
false ならフィルタリングを行い、そうでなければ * を付けて返すような感じ。
こんなアプローチもありかな。