背景の質問: 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> > >
>
{};
上記は、すべてのベクトルがポインターに置き換えられたツリーの作成に成功しました。ここまでは順調ですね。ここで、反復子をインクリメントしてみます。イテレータを進めるほうがよいことに気付いたので、1 つの変換だけで、ランダム アクセス イテレータのほとんどの動作を得ることができました (逆参照は、もう 1 つの欠落している部分です)。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 無関係なこと:変換で少し遊んだ後、私が使用している一般的なパターンは次のとおりです。
- 木をどうするか決める
- 操作を実行するプリミティブ変換を作成する
- 変換が適用されるべき場所を認識する文法を書き、以前に定義された変換を使用します
これは合理的だと思いますか?つまり、単一の種類のノードに対して基本的な操作を実行するだけでも、大量のコードになります。コンテキストを使用すると、ノード タイプを区別して、一度に複数の op を定義できます。変換でもこれを行うことは可能ですか? 使用される一般的なパターンは何ですか?