2012-10-30 34 views
2

我正在試驗原始構建一個DSEL,它在幾何向量上運行。我正在嘗試編寫一個轉換,它將採用賦值表達式並將其展開爲明智的組件。舉例來說,我想Boost.Proto和複雜轉換

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

到目前爲止,我已經能夠更換

p = q + r; 

大多使其通過進行轉換模板unroll_vector_expr是遞歸解開表達對每個矢量分量工作結合distribute_subscript變換。

我似乎不明白什麼是與boost::result_ofresult_of::make_expr使用的'參數'的基本原理。文檔,示例和內部代碼似乎混合使用Expr,impl::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_type結果從operator()匹配,並且適用於terminal小號都是由價值和參考不放?

更新:代碼更新後埃裏克的答案。 result_typemake_expr之間僅存的失配是用於unroll_vector_expr_c第一實例化,其中terminal< mpl::size_t<0> >::typeconst引用而不是由保持。奇怪的是,後續的具有較高索引的相同模板的實例化不會導致這個問題。

更新:我設法得到的代碼工作充分,修改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 > 
    > 
{}; 

回答

3

一個快速的回答現在。我會盡量更仔細地看看你明天的轉變。

impl::exprimpl::expr_param的含義可以通過查看關於transform_impl的文檔來理解。簡而言之,在變換的operator()的簽名中使用impl::expr_param,因爲它會添加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

+0

我提到'deep_copy',因爲使用它會導致我的'result_type'和'make_expr'的實際結果不同。關於使用'boost :: ref'的觀點正是我對'make_expr'所缺少的東西,我只希望原始終端通過引用保存(一個保存在'state'中)。 –

+0

謝謝埃裏克,我終於能夠完成這項工作!您是否願意評論我爲什麼需要上次修復?無論何時你有時間,當然。 –

+0

'_make_subscript'是'proto :: functional :: make_expr '的一個typedef。像'proto :: result_of :: make_expr'一樣,它對它的參數是否是引用也很敏感。所以如果你想用'_make_subscript'來存儲一個孩子的價值,你必須確保它不是一個參考。你可能會想,「但是我將一個右值傳遞給'distribute_subscript'變換。爲什麼Proto認爲它是一個左值?」在C++ 03中,無法在其參數的右值上重載函數。所以'distribute_subscript :: operator()'推導出它的「狀態」參數是一個'const&'。 HTH –