【问题标题】:Filter the synthesized attribute through a std::map in a boost spirit semantic action在增强精神语义动作中通过 std::map 过滤合成属性
【发布时间】:2013-01-07 22:25:22
【问题描述】:

我有一个案例,我想通过 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 containers,这应该可以工作。但是我在规则行上得到一个编译错误。如果我用经典的毫无意义的[qi::_val = qi::_1] 替换语义操作,这个错误就会消失(不足为奇)。

MSVS10 下的编译器错误像往常一样长得令人震惊,但这是我的代码文件的第一次提及:(在 C:\code\Compiler2\spirit_test.cpp(25)... 第 25 行是规则 @987654324 @)

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

【问题讨论】:

  • 我不认为phx::at 是你想要的——那是为了访问(适应的)元组元素,而不是为了使用下标运算符。试试qi::_val = phx::ref(myMap)[qi::_1] 而不是qi::_val = phx::at(myMap, qi::_1)
  • @ildjarn:确实……这行得通!我想我认为它与 std::map .at(). 的工作方式相同
  • 啊,我想我把phx::atphx::at_c 混淆了(改编自Boost.Fusion)。你对phx::at 是正确的——我认为你所拥有的应该可以工作(可能需要qi::_val = phx::at(phx::ref(myMap), qi::_1))。很高兴解决方法有所帮助。 :-]
  • 请注意,phx::at(phx::ref(myMap), qi::_1) 会产生另一组较长的错误...从该错误消息的外观来看,此版本的 at 显然返回一对/元组...不确定是否这是疏忽或故意的。
  • std::map::at 是 C++11 的新成员,因此 Boost.Phoenix 可能还不支持它(或者至少从 Boost 1.50.0 开始)。 :-]

标签: c++ boost boost-spirit boost-spirit-qi


【解决方案1】:

从评论转发

尝试qi::_val = phx::ref(myMap)[qi::_1] 而不是qi::_val = phx::at(myMap, qi::_1)

【讨论】:

    【解决方案2】:

    问题是phoenix::at 的返回类型在this header 中定义为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";
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-20
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多