我正在尝试使用 Proto 来构建一个对几何向量进行操作的 DSEL 。我正在尝试编写一个转换,它将采用一个赋值表达式并在组件方面展开它。例如,我想替换
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
变换。
我似乎不明白与boost::result_of
和result_of::make_expr
一起使用的'参数'的基本原理。文档,示例和内部代码似乎混合了Expr
,impl::expr
和impl::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_type
与operator ()
的结果匹配,并且适用于terminal
的值是按值还是通过引用保存?
更新: Eric 的回答后更新了代码。 result_type
和make_expr
之间唯一的不匹配是 unroll_vector_expr_c
的第一次实例化,其中terminal< mpl::size_t< 0 > >::type
由 const引用保存而不是 value 。奇怪的是,具有更高索引的相同模板的后续实例化不会导致此问题。
更新:在修改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 >
>
{};
答案 0 :(得分:3)
现在快速回答。我明天会试着更仔细地看看你的转变。
通过查看transform_impl
的文档,可以理解impl::expr
和impl::expr_param
的含义。简而言之,在变换impl::expr_param
的签名中使用operator()
,因为它会添加const &
以确保表达式在传递给函数时不会被复制。在类型计算中使用Expr
,例如boost::result_of
。 impl::expr
没有多大用处,可以忽略不计。
至于deep_copy
总是迫使您的终端按价值持有,这几乎是deep_copy
的用途。但也许你的意思是别的,因为我在你的代码中没有看到deep_copy
。
关于make_expr
的一句话:它强迫您非常仔细地考虑 应该通过引用存储哪些节点以及按值存储哪些节点。在类型计算(result_of::make_expr
)中,引用类型是应该通过引用保存的东西,但在实际的函数调用(proto::make_expr
)中,如果需要,必须用boost::ref
包装内容然后通过参考。这很奇怪。查看make_expr
的用户文档。