Boost.Spirit.Qiで引数を取るようなrule・・・でいいのかな?

typedef qi::rule<Iterator, unsigned int(), ascii::space_type>    rule_t;
 
rule_t  XXX_; 
rule_t  YYY_;
rule_t  ZZZ_;
 
XXX_    %= qi::omit[qi::no_case[ascii::string("XXX")] >> *qi::blank >> "=" >> *qi::blank] >> qi::uint_;
YYY_    %= qi::omit[qi::no_case[ascii::string("YYY")] >> *qi::blank >> "=" >> *qi::blank] >> qi::uint_;
ZZZ_    %= qi::omit[qi::no_case[ascii::string("ZZZ")] >> *qi::blank >> "=" >> *qi::blank] >> qi::uint_;
//        |                                                                             |
//↓      +------------------------この部分をまとめたい---------------------------------|
//
XXX_    %= omitted("XXX") >> qi::uint_;
YYY_    %= omitted("YYY") >> qi::uint_;
ZZZ_    %= omitted("ZZZ") >> qi::uint_;

↑こんな風にしたかった。
つまり、文字列を引数に取るqi::ruleが欲しかったわけで。


Twitterで聞いたら[twitter:@kikairoya]さんからqi::_rNを使う方法を教えてもらった。

_r1, _r2... , _rN
The enclosing rule's Nth inherited attribute.

http://www.boost.org/doc/libs/1_47_0/libs/spirit/doc/html/spirit/qi/quick_reference/phoenix.html
typedef qi::rule<iterator, void(std::string), ascii::space_type> subrule_type; //(1)
typedef qi::rule<iterator, unsigned(), ascii::space_type> rule_type;
 
int main() {
    subrule_type omitted;
    omitted %= qi::omit[qi::no_case[ascii::string(qi::_r1)] >> *qi::blank >> "=" >> *qi::blank]; //(2)
    rule_type x, y;
    x %= omitted(std::string("XXX")) >> qi::uint_;
    y %= omitted(std::string("YYY")) >> qi::uint_;
    const std::string s = "XXX=3";
    iterator ite = s.begin();
    unsigned res = 0;
    qi::phrase_parse(ite, s.end(), x, ascii::space, res);
    std::cout << res << std::endl;
}

※)頂いたコードを一部改変

(1)subrule_typeのtypedefのところでvoid(std::string)という風にして、
(2)そのruleを定義するときにqi::_r1で受け取ればいいらしい。


さらに、omitted(std::string("XXX"))のstd::stringが冗長だと思って、どうにかしようとしたらこんな風に。

omitted     %=
    qi::omit[
        qi::no_case[
            ascii::string(
                phoenix::construct<std::string>(
                    qi::_r1))] >> *qi::blank >> "=" >> *qi::blank];

phoenixを使って、引数に文字列が渡されたら、それからstd::stringを構築する。
ただし、残念なことに

XXX_    %= omitted_("XXX") >> qi::uint_;

とかやっても

C:\boost\boost_1_46_1\boost/fusion/container/vector/detail/vector_n.hpp(50) : error C2536: 'boost::fusion::vector_data1::boost::fusion::vector_data1::m0' : クラス、構造体、共用体のメンバは、初期化できません。
with
[
T0=const char [4]
]
C:\boost\boost_1_46_1\boost/fusion/container/vector/detail/vector_n.hpp(71) : 'boost::fusion::vector_data1::m0' の宣言を確認してください。
with
[
T0=const char [4]
]
C:\boost\boost_1_46_1\boost/fusion/container/vector/detail/vector_n.hpp(50): クラス テンプレート のメンバ関数 'boost::fusion::vector_data1::vector_data1(const boost::fusion::vector_data1 &)' のコンパイル
with
[
T0=const char [4]
]
C:\boost\boost_1_46_1\boost/fusion/container/vector/detail/vector_n.hpp(77) : コンパイルされたクラスの テンプレート のインスタンス化 'boost::fusion::vector_data1' の参照を確認してください
with
......

とか怒られちゃう(const charの配列が渡されてるのがよくない?)ので強制的にchar const *に変換すれば・・・いいのかしら・・・

XXX_    %= omitted_(&*"XXX") >> qi::uint_;