背景问题:boost.proto + detect invalid terminal before building the expression tree。boost.proto +修改表达式树
嗨,我想要做到的,是
- 创建一个表达式树,所有的向量取代有 他们开始迭代器的副本(在我的情况是一个原始指针)
- 增加迭代器到树中,但该部分应该相对容易。
所以,对于1.我结束了这段代码
///////////////////////////////////////////////////////////////////////////////
// A transform that converts all vectors nodes in a tree to iterator nodes
struct vector_begin : proto::transform <vector_begin>
{
template<typename Expr, typename Unused1, typename Unused2>
struct impl : boost::proto::transform_impl<Expr, Unused1, Unused2>
{
// must strip away the reference qualifier (&)
typedef typename proto::result_of::value<
typename boost::remove_reference<Expr>::type
>::type vector_type;
typedef typename proto::result_of::as_expr
<typename vector_type::const_iterator>::type result_type;
result_type operator()(
typename impl::expr_param var
, typename impl::state_param
, typename impl::data_param) const
{
typename vector_type::const_iterator iter(proto::value(var).begin());
return proto::as_expr(iter); // store iterator by value
}
};
};
struct vector_grammar_begin
: proto::or_ <
proto::when <vector_terminal, vector_begin>
// scalars want to be stored by value (proto stores them by const &), if not the code does not compile...
, proto::when <scalar_terminal, boost::proto::_make_terminal(boost::proto::_byval(boost::proto::_value))>
// descend the tree converting vectors to begin() iterators
, proto::when <proto::nary_expr<_, proto::vararg<vector_grammar_begin> > >
>
{};
以上成功创建所有矢量由指针取代了树。到现在为止还挺好。现在,尝试增加 迭代器。我意识到提升迭代器会更好,所以只需一次转换,我就可以获得随机访问迭代器的大部分行为(取消引用是另一个缺失的部分)。对于2,所需的转换应该是
///////////////////////////////////////////////////////////////////////////////
// A transform that advances all iterators in a tree
struct iter_advance : proto::transform <iter_advance>
{
template<typename Expr, typename Index, typename Dummy>
struct impl : boost::proto::transform_impl<Expr, Index, Dummy>
{
typedef void result_type;
result_type operator()(
typename impl::expr_param var
, typename impl::state_param index // i'm using state to pass a data :(
, typename impl::data_param) const
{
proto::value(var)+=index; // No good... compile error here :(
}
};
};
// Ok, this is brittle, what if I decide the change vector<D,T>'s iterator type ?
struct iter_terminal
: proto::and_<
proto::terminal<_>
, proto::if_<boost::is_pointer<proto::_value>()>
>
{};
struct vector_grammar_advance
: proto::or_ <
proto::when <iter_terminal, iter_advance>
, proto::terminal<_>
, proto::when <proto::nary_expr<_, proto::vararg<vector_grammar_advance> > >
>
{};
现在,在主要功能
template <class Expr>
void check_advance (Expr const &e)
{
proto::display_expr (e);
typedef typename boost::result_of<vector_grammar_begin(Expr)>::type iterator_type;
iterator_type iter = vector_grammar_begin()(e);
proto::display_expr (iter);
vector_grammar_advance()(iter,1);
proto::display_expr (iter);
}
int main (int, char**)
{
vec<3, double> a(1), b(2), c(3);
check_advance(2*a+b/c);
return 0;
}
我收到以下错误消息(过滤掉垃圾):
array.cpp: 361:13:错误:只读位置的分配
'boost::proto::value<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<const double*>, 0l> >((* & var))'
让我困扰的是“((* & var))'部分...不知道该怎么做才能解决这个问题。 在此先感谢,最好的问候
PS 无关的事:打一点与转换之后,我使用的一般模式是:
- 决定做什么树
- 编写一个执行操作的基本转换
- 编写一个语法,用于识别应该应用转换的位置,使用之前定义的转换
你认为这是否合理?我的意思是,执行一个简单的节点类型的代码很多。通过上下文,可以一次定义多个操作,区分节点类型。 也可以用变换来做到这一点?什么是一般的使用模式?
错误消息意味着'var'(你试图通过'index'增加它)是不可变的。您是否尝试过使用更实用的样式,其中的变换会返回下一个迭代器? –
@LucDanton尝试了,如果我在iter_advance中更改返回类型并返回一个修改过的指针(我已验证指针在变换中增加了),树不会更改。我正在关注proto的manual上的'increment_ints',但是现在我意识到它不同,在这种情况下,树存储对int变量的引用,现在我已经将ptrs按值存储在树中。替代方案:1.每增加一次,我就增加整个树的新副本(纯功能方法?)b)将指针存储在iterator_wrapper中,就像手册的“混合”示例一样。 – Giuliano