背景問題: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