我正在尝试与Proto一起构建可在几何 vector 上运行的DSEL。我正在尝试编写一个转换,该转换将采用一个assign表达式并将其展开为组件。例如,我要替换

p = q + r;

通过
p[0] = q[0] + r[0],
p[1] = q[1] + r[1],
...,
p[N] = q[N] + r[N],
p;

到目前为止,我已经能够通过制作一个转换模板unroll_vector_expr使其与distribute_subscript转换一起递归展开每个 vector 分量的表达式来使它工作。

我似乎不明白boost::result_ofresult_of::make_expr使用的“参数”的原理是什么。文档,示例和内部代码似乎混合了Exprimpl::exprimpl::expr_param。我不确定应该使用什么以及何时使用,以便result_type与实际结果类型匹配。目前,我通过检查错误消息并修复const&差异使它通过尝试错误来工作。但是,一旦我深深复制该表达式,该终端将不再被引用保留,并且我的代码将失败。
struct distribute_subscript
  : or_<
        scalar_grammar
      , when<
            vector_literal
          , _make_subscript( _, _state )
        >
      , plus< distribute_subscript, distribute_subscript >
      , minus< distribute_subscript, distribute_subscript >
      , multiplies< distribute_subscript, distribute_subscript >
      , divides< distribute_subscript, distribute_subscript >
      , assign< distribute_subscript, distribute_subscript >
    >
{};

template< std::size_t I, std::size_t N >
struct unroll_vector_expr_c;

template< std::size_t I, std::size_t N >
struct unroll_vector_expr_c
  : transform< unroll_vector_expr_c< I, N > >
{
    template< typename Expr, typename State, typename Data >
    struct impl
      : transform_impl< Expr, State, Data >
    {
        typedef
            typename result_of::make_expr<
                tag::comma
              , typename boost::result_of<
                    distribute_subscript(
                        Expr
                      , typename result_of::make_expr<
                            tag::terminal
                          , boost::mpl::size_t< I - 1 >
                        >::type
                    )
                >::type
              , typename boost::result_of<
                    unroll_vector_expr_c< I + 1, N >(
                        Expr
                    )
                >::type
            >::type
            result_type;

        result_type operator ()(
            typename impl::expr_param expr
          , typename impl::state_param state
          , typename impl::data_param data
        ) const
        {
            return
                make_expr< tag::comma >(
                    distribute_subscript()(
                        expr
                      , make_expr< tag::terminal >(
                            boost::mpl::size_t< I - 1 >()
                        )
                    )
                  , unroll_vector_expr_c< I + 1, N >() (
                        expr
                    )
                );
        }
    };
};

template< std::size_t N >
struct unroll_vector_expr_c< N, N >
  : transform< unroll_vector_expr_c< N, N > >
{
    template< typename Expr, typename State, typename Data >
    struct impl
      : transform_impl< Expr, State, Data >
    {
        typedef
            typename boost::result_of<
                distribute_subscript(
                    Expr
                  , typename result_of::make_expr<
                        tag::terminal
                      , boost::mpl::size_t< N - 1 >
                    >::type
                )
            >::type
            result_type;

        result_type operator ()(
            typename impl::expr_param expr
          , typename impl::state_param state
          , typename impl::data_param data
        ) const
        {
            return
                distribute_subscript()(
                    expr
                  , make_expr< tag::terminal >(
                        boost::mpl::size_t< N - 1 >()
                    )
                );
        }
    };
};

struct unroll_vector_expr
  : transform< unroll_vector_expr >
{
    template< typename Expr, typename State, typename Data >
    struct impl
      : transform_impl< Expr, State, Data >
    {
        typedef
            typename dimension<
                typename boost::remove_reference<
                    typename boost::result_of<
                        _value( State )
                    >::type
                >::type
            >::type
            dimension;

        typedef
            typename result_of::make_expr<
                tag::comma
              , typename boost::result_of<
                    unroll_vector_expr_c< 1, dimension::value >(
                        Expr
                    )
                >::type
              , State
            >::type
            result_type;

        result_type operator ()(
            typename impl::expr_param expr
          , typename impl::state_param state
          , typename impl::data_param data
        ) const
        {
            return
                make_expr< tag::comma >(
                    unroll_vector_expr_c< 1, dimension::value >()(
                        expr
                    )
                  , boost::ref( state )
                );
        }
    };
};

我应该如何编写自己的转换,以便result_typeoperator ()的结果匹配,并适用于按值和按引用保存的terminal

更新:代码在Eric回答后更新。 result_typemake_expr之间唯一剩余的不匹配是unroll_vector_expr_c的第一个实例化,其中terminal< mpl::size_t< 0 > >::type由const引用而不是按值保存。奇怪的是,具有更高索引的同一模板的后续实例化不会导致此问题。

更新:在修改了distribue_subscript转换以强制按值获取下标索引后,我设法使代码完全正常工作:
struct distribute_subscript
  : or_<
        scalar_grammar
      , when<
            vector_literal
          , _make_subscript( _, _byval( _state ) ) // <-- HERE
        >
      , plus< distribute_subscript, distribute_subscript >
      , minus< distribute_subscript, distribute_subscript >
      , multiplies< distribute_subscript, distribute_subscript >
      , divides< distribute_subscript, distribute_subscript >
      , assign< distribute_subscript, distribute_subscript >
    >
{};

最佳答案

现在快速回答。明天我将尝试更仔细地研究您的转换。

可以通过查看 impl::expr 的文档来了解impl::expr_paramtransform_impl的含义。简而言之,请在转换的impl::expr_param的签名中使用operator(),因为它添加了const &以确保将表达式传递给函数时不会被复制。像Expr一样,在类型计算中使用boost::result_ofimpl::expr的用处不大,可以忽略。

至于deep_copy总是强制您的终端按值持有,这几乎就是deep_copy的用途。但是也许您的意思是别的,因为我的代码在任何地方都看不到deep_copy

关于make_expr的一句话:它迫使您非常仔细地考虑应该通过引用存储哪些节点,以及通过值存储哪些节点。在类型计算(result_of::make_expr)中,引用类型是应该由引用保留的事物,但是在实际的函数调用(proto::make_expr)中,如果要随后由引用保留,则必须用boost::ref包装事物。真奇怪检查用户文档 make_expr

关于c++ - Boost.Proto和复杂变换,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13146537/

10-11 16:36