Boost.Variant で特定の型の値に対して処理を行う
初 C++。
上記の記事では
- apply<{期待する variant が保持する値の型}>({variant な変数}, {適用したい関数})
という定義になっていたのですが、これを
- apply({variant な変数}, {期待する variant が保持する値の型を受け取る関数})
と、いう風にしてみました。
[ソース]
#include <boost/variant.hpp> #include <boost/optional.hpp> #include <boost/function_types/parameter_types.hpp> #include <boost/function_types/result_type.hpp> template<typename F, typename R> struct apply_visitor : F{ apply_visitor(F const& f) : F(f){ } using F::operator(); typedef boost::optional<R> result_type; template<typename T> result_type operator ()(T) const{ return boost::none; } }; template<typename F> struct apply_visitor<F, void> : F{ typedef void result_type; apply_visitor(F const& f) : F(f){ } using F::operator(); template<typename T> void operator ()(T) const{} }; template< typename T, typename F, typename Result = typename boost::function_types::result_type<decltype(&F::operator())>::type, typename Visitor = apply_visitor<F, Result> > typename Visitor::result_type apply(T const& variant, F func){ return boost::apply_visitor(Visitor{ func }, variant); } template< typename T, typename F, typename Result = typename boost::function_types::result_type<decltype(&F::operator())>::type, typename Visitor = apply_visitor<F, Result> > typename Visitor::result_type apply(T& variant, F func){ return boost::apply_visitor(Visitor{ func }, variant); } #include <iostream> #include <boost/optional/optional_io.hpp> template<typename Op> void print_optional(Op op){ if( op ){ std::cout << op << std::endl; } else{ std::cout << "NONE" << std::endl; } } int main(){ typedef boost::variant<int, float, char> var_type; var_type v1{42}; var_type v2{3.14f}; print_optional(apply(v1, [](int n ){ return n * n; })); print_optional(apply(v2, [](int n ){ return n * n; })); print_optional(apply(v1, [](float f){ return f + f; })); print_optional(apply(v2, [](float f){ return f + f; })); print_optional(apply(v1, [](int){ return "int"; })); print_optional(apply(v2, [](int){ return "int"; })); apply(v1, [](int& n){ std::cout << n << std::endl; n = 10; }); std::cout << v1 << std::endl; return 0; }
[出力]
1764 NONE NONE 6.28 int NONE 42 10
面倒臭かったので関数オブジェクトしか受け取る事を考えていませんが、Generic Lambda も必要がないので C++11 でも動作しますね。
apply_visitor の戻り値型を optional にするのは有効っすなー。