読者です 読者をやめる 読者になる 読者になる

Oven Rangeアダプタのプレースホルダーを置き換えてるところ

C++

解析メモです。

以下のコードを評価する流れを調べます。

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で動かないのはなぜでしょう。


コンパイルエラーになる過程をステップ実行できるコンパイル時デバッガがほしいです・・・。