解析メモです。
以下のコードを評価する流れを調べます。
std::vector<int> v;
v | filtered(is_even());
まずfilteredの型。
// <pstade/oven/filtered.hpp> namespace pstade { namespace oven { namespace filtered_detail { ... } PSTADE_OVEN_BASE_TO_ADAPTOR(filtered, (filtered_detail::base<_, _>)) }}
このマクロを展開するとこうなる。
namespace adaptor_workarea_of_filtered { using namespace boost::mpl::placeholders; typedef pstade::egg::deferred< pstade::unparenthesize_detail::aux< void (::pstade::unparenthesize_detail::klass::*) (filtered_detail::base<_, _>) >::type >::type op; } typedef adaptor_workarea_of_filtered::op T_make_filtered; ... pstade::unparenthesize_detail::aux< void (::pstade::unparenthesize_detail::klass::*) (T_make_filtered) >::type const __attribute__ ((__unused__)) make_filtered = {{}}; ... pstade::unparenthesize_detail::aux< void (::pstade::unparenthesize_detail::klass::*) (pstade::egg::result_of_pipable<T_make_filtered>::type) >::type const __attribute__ ((__unused__)) filtered = { { {{}} , {} } }; } }
pstade::egg::result_of_pipeableはegg::functionを返す。
// <pstade/egg/pipeable.hpp> namespace pstade { namespace egg { template<class Base, class Strategy = by_perfect> struct result_of_pipable { typedef function<detail::little_pipable_result<Base, Strategy>, Strategy> type; }; }}
ここで範囲に対してRangeアダプタをoperator|()でつなぐ。
テンプレートパラメータBaseにはpstade::oven::filtered_detail::base<_, _>のような型が入ってくる。
// <pstade/egg/detail/little_pipeable_result.hpp> namespace pstade { namespace egg { namespace detail { namespace little_pipable_resultns_ { template<class A, class Base, class ArgTuple> struct result_of_output : result_of< typename result_of<T_fuse(Base const&)>::type(boost::tuples::cons<A&, ArgTuple>) > { }; template<class A, class Base, class Strategy, class ArgTuple> inline typename result_of_output<A, Base, ArgTuple>::type operator|(A& a, function<little_pipable_result<Base, Strategy, ArgTuple>, Strategy> const& pi) { return fuse(pi.little().m_base)(here::tuple_push_front(pi.little().m_arguments, a)); } template<class A, class Base, class Strategy, class ArgTuple> inline typename result_of_output<PSTADE_DEDUCED_CONST(A), Base, ArgTuple>::type operator|(A const& a, function<little_pipable_result<Base, Strategy, ArgTuple>, Strategy> const& pi) { return fuse(pi.little().m_base)(here::tuple_push_front(pi.little().m_arguments, a)); } } }}}
fuseの型はこれ。
// <pstade/egg/fuse.hpp> namespace pstade { namespace egg { typedef generator< result_of_fuse< deduce<boost::mpl::_1, as_value> >::type, boost::use_default, use_brace2, by_value >::type T_fuse; }}
generatorメタ関数はlittle_generatorのfunctionを作る。
// <pstade/egg/generator.hpp> namespace pstade { namespace egg { template< class Lambda, class NullaryResult = boost::use_default, class Make = boost::use_default, class Strategy = by_perfect > struct generator { typedef function<detail::little_generator<Lambda, NullaryResult, Make>, Strategy> type; }; }}
little_generatorのapplyメタ関数の中で評価してるgenerated_objectがboost::mpl::applyをしてプレースホルダーを置き換えてる。
applyで得られた型をlittle_generatorのoperator()で使う。この指定は外から行う。
// <pstade/egg/detail/little_generator.hpp> namespace pstade { namespace egg { namespace detail { template<class Lambda> struct is_placeholder_expression : boost::mpl::is_lambda_expression<Lambda> { }; template<class Lambda> struct lambda_to_dummy : boost::mpl::eval_if< is_placeholder_expression<Lambda>, template_arguments_of<Lambda>, boost::mpl::identity<Lambda> > { }; template<class Dummy, class Lambda> struct dummy_to_lambda : boost::mpl::eval_if< is_placeholder_expression<Lambda>, template_arguments_copy<Dummy, Lambda>, boost::mpl::identity<Dummy> > { }; template< class Lambda, class A0 = void , class A1 = void , class A2 = void , class A3 = void , class A4 = void > struct generated_object { typedef typename boost::remove_cv<Lambda>::type lambda_t; typedef typename boost::mpl::apply5< typename lambda_to_dummy<lambda_t>::type, A0 , A1 , A2 , A3 , A4 >::type dummy_t; typedef typename affect<Lambda, typename dummy_to_lambda<dummy_t, lambda_t>::type>::type type; }; template<class Lambda, class NullaryResult, class Make> struct little_generator { typedef typename if_use_default<Make, use_constructor>::type how_t; typedef NullaryResult nullary_result_type; template<class Result> Result call() const { return how_t()(boost::type<Result>()); } template<class Myself, class A0 , class A1 = void , class A2 = void , class A3 = void , class A4 = void , class A5 = void> struct apply; template<class Myself, class A0> struct apply<Myself, A0> : generated_object< Lambda, A0 > { }; template<class Result, class A0> Result call( A0 & a0) const { return how_t()(boost::type<Result>(), a0); } template<class Myself, class A0 , class A1> struct apply<Myself, A0 , A1> : generated_object< Lambda, A0 , A1 > { }; template<class Result, class A0 , class A1> Result call( A0 & a0 , A1 & a1) const { return how_t()(boost::type<Result>(), a0 , a1); } ... }; } } }
egg::functionのoperator()で、Little::template applyを評価するresultメタ関数を評価してる。
// <pstade/egg/detail/perfect_strategy_include.hpp> namespace pstade { namespace egg { template<class Little> struct function<Little, pstade::egg::by_perfect> { typedef function function_type; typedef Little little_type; Little m_little; Little little() const { return m_little; } typedef typename detail::nullary_result<Little, function>::type nullary_result_type; template<class FunCall> struct result; nullary_result_type operator()() const { return detail::call_little< Little, nullary_result_type >::call(m_little); } private: template< class A0> struct result1 : Little::template apply< Little const, typename detail::meta_arg<A0 >::type > { }; public: template<class Fun, class A0> struct result<Fun( A0)> : result1< A0 > { }; template< class A0> typename result1< A0 & >::type operator()( A0 & a0 ) const { return detail::call_little< Little, typename result1< A0 & >::type >::call(m_little, a0); } template< class A0> typename result1< A0 const & >::type operator()( A0 const & a0 ) const { return detail::call_little< Little, typename result1< A0 const & >::type >::call(m_little, a0) } private: template< class A0 , class A1> struct result2 : Little::template apply< Little const, typename detail::meta_arg<A0 >::type , typename detail::meta_arg<A1 >::type > { }; public: template<class Fun, class A0 , class A1> struct result<Fun( A0 , A1)> : result2< A0 , A1 > { }; template< class A0 , class A1> typename result2< A0 & , A1 & >::type operator()( A0 & a0 , A1 & a1 ) const { return detail::call_little< Little, typename result2< A0 & , A1 & >::type >::call(m_little, a0 , a1); } template< class A0 , class A1> typename result2< A0 & , A1 const & >::type operator()( A0 & a0 , A1 const & a1 ) const { return detail::call_little< Little, typename result2< A0 & , A1 const & >::type >::call(m_little, a0 , a1); } template< class A0 , class A1> typename result2< A0 const & , A1 & >::type operator()( A0 const & a0 , A1 & a1 ) const { return detail::call_little< Little, typename result2< A0 const & , A1 & >::type >::call(m_little, a0 , a1); } template< class A0 , class A1> typename result2< A0 const & , A1 const & >::type operator()( A0 const & a0 , A1 const & a1 ) const { return detail::call_little< Little, typename result2< A0 const & , A1 const & >::type >::call(m_little, a0 , a1); } ... }; } }
これでfiltered_detail::base<_, _>のプレースホルダーが置き換えられる。
さて、これがGCC 4.5で動かないのはなぜでしょう。
コンパイルエラーになる過程をステップ実行できるコンパイル時デバッガがほしいです・・・。