3

boost::spirit ルール定義のアクション内から (まだ) 不明なインスタンスのメンバーを参照しようとしているので、疑似コードでは、

double_[ref(rN) = _1] の代わりに X** ppx; のようなものを探しています。double_[ref(&X::rN, ppx) = _1]

その回避策は、インスタンスを認識し、それに書き込むことができるパラメーターを使用した単純な「セマンティックアクション」である可能性があります。

qi::rule<Iterator, Skipper> start;
my_grammar(DataContext*& dataContext) : my_grammar::base_type(start) , execContext(execContext) {
    start = qi::double_[ boost::bind(&my_grammar::newValueForXY, dataContext, ::_1) ];

ただし、「phoenix::ref(...) = value」を使用して「ローカル」変数にバインドできるように、メンバー変数に直接「バインド」できる可能性があるかどうか疑問に思っています。

次の構文を試しました。

start = qi::int_[ boost::bind<int&>(&DataContext::newValueForXY, boost::ref(dataContext))() = ::_1] ];

VS2010SP1とエラーメッセージで失敗しました

エラー C2440: '=': 'boost::arg' は ... に変換できません

4

1 に答える 1

9

この猫の皮を剥ぐ方法はいくつかあります:

  1. あなたはおそらくバインド式の実行を延期することを考えました:phx::bindそれはできます
  2. または、そのために属性の伝播を使用することもできます(セマンティックアクションをまったく使用しません) 。
  3. 最後に、継承された属性を使用できます(たとえば、DataContext に既定のコンストラクターがない場合や、コピーにコストがかかる場合) 。

1.フェニックスでバインドを延期する

この目的のために phoenix バインドを使用します。これにより、セマンティック アクションがトリガーされた時点で「遅延実行」される Phoenix アクターが生成されます。

以下は、あなたが探していたかもしれない不足しているコード サンプルの再構築です。

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;

struct DataContext
{
    double xy;
};

template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator, Skipper>
{
    my_grammar(DataContext& dataContext) : my_grammar::base_type(start)
    {
        start = qi::double_
            [ phx::bind(&my_grammar::newValueForXY, 
                    phx::ref(dataContext), 
                    qi::_1) ];
    }
  private:
    static void newValueForXY(DataContext& dc, double value)
    {
         dc.xy = value;
    }

    qi::rule<Iterator, Skipper> start;
};

int main()
{
    const std::string s = "3.14";

    DataContext ctx;

    my_grammar<decltype(begin(s)), qi::space_type> p(ctx);
    auto f(begin(s)), l(end(s));
    if (qi::phrase_parse(f, l, p, qi::space))
        std::cout << "Success: " << ctx.xy << "\n";
}

ノート:

  • phx::ref() は、データコンテキストへの参照をラップします
  • プレースホルダーとして boost::_1 の代わりに qi::_1
  • この実装を考えるnewValueForXYと、簡単に書くことができます

        start = qi::double_
            [ phx::bind(&DataContext::xy, phx::ref(dataContext)) = qi::_1 ];
    

2. セマンティック アクションの代わりに属性文法を使用する

ただし、セマンティック アクションの代わりに属性を使用して、おそらく同じ例を記述します (基本的に属性が目的であるため)。

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;

struct DataContext {
    double xy;
};

BOOST_FUSION_ADAPT_STRUCT(DataContext, (double, xy))

template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator, DataContext(), Skipper>
{
    my_grammar() : my_grammar::base_type(start) {
        start = qi::double_;
    }
  private:
    qi::rule<Iterator, DataContext(), Skipper> start;
};

int main()
{
    const std::string s = "3.14";
    static const my_grammar<decltype(begin(s)), qi::space_type> p;

    DataContext ctx;
    if (qi::phrase_parse(begin(s), end(s), p, qi::space, ctx))
        std::cout << "Success: " << ctx.xy << "\n";
}

3. 継承された属性を使用してコンテキスト参照を渡す

絶対に主張する場合inherited attributesは、目的に使用することもできます:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;

struct DataContext {
    double xy;
};

template <typename Iterator, typename Skipper>
struct my_grammar : qi::grammar<Iterator, void(DataContext&), Skipper> {
    my_grammar() : my_grammar::base_type(start) 
    {
        start = qi::double_ [ phx::bind(&DataContext::xy, qi::_r1) = qi::_1 ];
    }
    qi::rule<Iterator, void(DataContext&), Skipper> start;
};

int main() {
    const std::string s = "3.14";
    const static my_grammar<std::string::const_iterator, qi::space_type> p;
    DataContext ctx;
    if(qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space)) {
        std::cout << "Success: " << ctx.xy << "\n";
    }
}

これは、呼び出しサイトでいくらか表現力があります。

qi::phrase_parse(begin(s), end(s), p(phx::ref(ctx)), qi::space));

コンテキストがデフォルトで構築可能である必要はありません。

于 2013-05-21T18:38:43.097 に答える