9

Boost.Spirit を学習しようとしていますが、問題が見つかりました。

文字列を次の構造に解析しようとしています。

struct employee {
    std::string name;
    std::string location;
};

そして、同じタイプの 2 つの属性が背中合わせにある場合、それらは (論理的に)std::vectorそのタイプの に折りたたまれているようです。そのルールのため、次のパーサー

+x3::ascii::alnum >>
    +x3::space >>
    +x3::ascii::alnum

の属性を持つことになりますstd::vector<std::string>

しかし、私は this を that に解析しようとしてstructいます。つまり、私にとって理想的な属性は aboost::fusion::tuple<std::string, std::string>であるため、構造体をそれに適応させることができます。

動作しないコードの完全版 (上記参照):

// Example program
#include <iostream>
#include <string>

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>


struct employee {
    std::string name;
    std::string location;
};

BOOST_FUSION_ADAPT_STRUCT(employee, 
    (std::string, name),
    (std::string, location)
)

namespace x3 = boost::spirit::x3;

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def = 
    +x3::ascii::alnum >>
    +x3::space >>
    +x3::ascii::alnum
    ;
BOOST_SPIRIT_DEFINE(parse_emp);

int main()
{
    std::string input = "Joe Fairbanks";
    
    employee ret;
    
    x3::parse(input.begin(), input.end(), parse_emp, ret);
    
    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}

生で見る

static_assertこのコードは、属性が正しくないことを通知するトリガーとなります。

error: static_assert failed "Attribute does not have the expected size."

のコマンドで

clang++ -std=c++14 test.cpp

(GCC でも失敗します)。

私が試したこと

この問題の回避策を見つけましたが、面倒で、これが最もクリーンな方法だとは信じられません。

// Example program
#include <iostream>
#include <string>

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>


struct employee {
    std::string name;
    std::string location;
};

namespace x3 = boost::spirit::x3;

x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def = 
    x3::eps [
    ([](auto& ctx) {
        x3::_val(ctx) = employee{};
    })
    ]>>
    (+x3::ascii::alnum)[
    ([](auto& ctx) {
        x3::_val(ctx).name = x3::_attr(ctx);
    })
    ]>>
    +x3::space >>
    (+x3::ascii::alnum)[
    ([](auto& ctx) {
        x3::_val(ctx).location = x3::_attr(ctx);
    })
    ]
    ;
BOOST_SPIRIT_DEFINE(parse_emp);

int main()
{
    std::string input = "Joe Fairbanks";
    
    employee ret;
    
    x3::parse(input.begin(), input.end(), parse_emp, ret);
    
    std::cout << "Name: " << ret.name << "\tLocation: " << ret.location << std::endl;
}

生で見る

私は本当にその解決策が好きではありません:それは精神の驚くべき表現力を台無しにし、それを非常に醜くします。また、employee構造体に新しいフィールドを追加したい場合は、私のBOOST_FUSION_ADAPT_STRUCT,これははるかに簡単です。

問題は、同じタイプの 2 つの連続する属性を (できれば) と から にきれいに分割する方法がstd::vectorあるboost::fusion::vectorかどうかです。

ここまでやってくれてありがとう;)。

4

1 に答える 1