1

std::map を使用して、ルール内で合成された属性として表示される値をフィルター処理したい場合があります。

  • マップは事前に生成されており、解析中に変更されることはありません。
  • マップと実際のパーサーの性質により、ルックアップが失敗することはありません (ただし、実際の要素の数はかなり多い場合があります)。
  • この問題に完全に適した通常のアプローチ (シンボル テーブルを使用する) は、実際のケースには適していません。実際の問題では、検索は属性に基づいて条件付きで行われますが、この属性は解析のかなり後になるまで明らかになりません (多少削除されたルールで)。

私の試み:

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <map>

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

int main() {

    std::map<unsigned int, unsigned int> myMap;
    myMap[1] = 100; myMap[2] = 200; myMap[3] = 300;

    std::string test = "1 2 3";
    std::vector<unsigned int> results;

    qi::rule<std::string::iterator, unsigned int()> r
                      = qi::uint_ [qi::_val = phx::at(myMap, qi::_1)];

    qi::parse(test.begin(), test.end(), ( r % " " ), results);

    BOOST_FOREACH(unsigned int &x, results) {
        std::cout << x << "\n";
    }
}

stl コンテナのフェニックスサポートにより、これはうまくいくはずだという印象を受けていたと思います。しかし、ルール行でコンパイル エラーが発生します。セマンティック アクションを従来の無意味なアクションに置き換えると、このエラーは[qi::_val = qi::_1]なくなります (驚くことではありません)。

いつものように、MSVS10 でのコンパイラ エラーは驚くほど長いですが、これが私のコード ファイルの最初の言及です: (C:\code\Compiler2\spirit_test.cpp(25)... 行 25 がルールですr)

C:\boost_1_50_0\boost/spirit/home/qi/nonterminal/rule.hpp(191) : see reference to function template instantiatio
n 'void boost::spirit::qi::rule<Iterator,T1>::define<boost::mpl::false_,Expr>(boost::spirit::qi::rule<Iterator,T1> &,con
st Expr &,boost::mpl::true_)' being compiled
        with
        [
            Iterator=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>,
            T1=unsigned int (void),
            Expr=boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript,boost::proto::argsns_::list2<const boo
st::spirit::terminal<boost::spirit::tag::uint_> &,const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::p
roto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,b
oost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost
::phoenix::detail::tag::function_eval,boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns
_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl::at_impl>,0>,boost::phoenix::actor<boost::proto::exprns
_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<std::map<unsigned
 int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::argument<0>>>,3>>>,2>> &>,2>
        ]
        C:\code\Compiler2\spirit_test.cpp(25) : see reference to function template instantiation 'boost::spirit::qi
::rule<Iterator,T1>::rule<boost::proto::exprns_::expr<Tag,Args,Arity>>(const Expr &,const std::string &)' being compiled

        with
        [
            Iterator=std::_String_iterator<char,std::char_traits<char>,std::allocator<char>>,
            T1=unsigned int (void),
            Tag=boost::proto::tagns_::tag::subscript,
            Args=boost::proto::argsns_::list2<const boost::spirit::terminal<boost::spirit::tag::uint_> &,const boost::ph
oenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::pro
to::exprns_::expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost:
:phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval,boost::proto::argsns_::list
3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl:
:at_impl>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::a
rgsns_::term<boost::reference_wrapper<std::map<unsigned int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::arg
ument<0>>>,3>>>,2>> &>,
            Arity=2,
            Expr=boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript,boost::proto::argsns_::list2<const boo
st::spirit::terminal<boost::spirit::tag::uint_> &,const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::p
roto::tagns_::tag::assign,boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,b
oost::proto::argsns_::term<boost::spirit::attribute<0>>,0>,boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost
::phoenix::detail::tag::function_eval,boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns
_::tag::terminal,boost::proto::argsns_::term<boost::phoenix::stl::at_impl>,0>,boost::phoenix::actor<boost::proto::exprns
_::basic_expr<boost::proto::tagns_::tag::terminal,boost::proto::argsns_::term<boost::reference_wrapper<std::map<unsigned
 int,unsigned int>>>,0>>,boost::phoenix::actor<boost::spirit::argument<0>>>,3>>>,2>> &>,2>
        ]
C:\boost_1_50_0\boost/proto/transform/default.hpp(154) : error C2440: '=' : cannot convert from 'std::pair<_Ty1,_Ty2>' t
o 'unsigned int'
        with
        [
            _Ty1=const unsigned int,
            _Ty2=unsigned int
        ]
        No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
4

2 に答える 2

3

コメントから転載

qi::_val = phx::ref(myMap)[qi::_1]ではなく試してみてくださいqi::_val = phx::at(myMap, qi::_1)

于 2013-01-07T22:52:40.960 に答える
2

問題は、このヘッダーで phoenix::at の戻り値の型がとして定義されていることcontainer::value_typeです。これはマップの場合のペアです。map の結果を特殊化するだけで機能します (ildjarn が指摘したように ref を使用)。

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/foreach.hpp>
#include <string>
#include <iostream>
#include <vector>
#include <map>

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

namespace boost { namespace phoenix { namespace stl {
    template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
        struct at_impl::result<This(std::map<Key,Value,Compare,Allocator>&, Index)>
        {
            typedef Value & type;
        };
    template <typename This, typename Key, typename Value, typename Compare, typename Allocator, typename Index>
        struct at_impl::result<This(std::map<Key,Value,Compare,Allocator> const&, Index)>
        {
            typedef Value const& type;
        };
}}}

int main() {

    std::map<unsigned int, unsigned int> myMap;
    myMap[1] = 100; myMap[2] = 200; myMap[3] = 300;

    std::string test = "1 2 3";
    std::vector<unsigned int> results;

    qi::rule<std::string::iterator, unsigned int()> r
                      = qi::uint_ [qi::_val = phx::at(phx::cref(myMap), qi::_1)];

    qi::parse(test.begin(), test.end(), ( r % " " ), results);

    BOOST_FOREACH(unsigned int &x, results) {
        std::cout << x << "\n";
    }
}
于 2013-01-08T00:27:03.033 に答える