在上下文参数的精神解析器操作中编译boost :: bind(成员函数)上的错误

时间:2016-06-16 23:21:32

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

我使用vc14和boost版本是1.60。

#include <boost/config/warning_disable.hpp>
#include <boost\spirit\home\qi.hpp>
#include <boost\variant.hpp>
#include <boost\spirit\include\qi.hpp>
#include <boost\spirit\include\phoenix_core.hpp>
#include <boost\spirit\include\phoenix_operator.hpp>
#include <boost\spirit\include\phoenix_object.hpp>
#include <boost/phoenix/function/adapt_function.hpp>
#include <boost\spirit\include\phoenix_fusion.hpp>
#include <boost\foreach.hpp>
#include <string>
#include <list>
#include <boost\bind.hpp>
#define BOOST_SPIRIT_USE_PHOENIX_V3


namespace testParser {
        namespace qi = boost::spirit::qi;
        namespace ascii = boost::spirit::ascii;
        namespace sp = boost::spirit;
        namespace fu = boost::fusion;
        typedef sp::context<
            fu::cons<std::list<std::string>,fu::nil >,
            fu::vector0<> 
        >  context;

        class str_menager
        {
            qi::symbols<char> const& vistrings;

        public:
            typedef void result_type;
                        typedef void type;
            str_menager(qi::symbols<char> const& ss) :vistrings(ss) {  }
            void operator ()(std::string const& s, context& con, bool& m_Flag)
            {
                if (vistrings.find(s) != nullptr)
                {
                    using boost::phoenix::at_c;
                    (fu::at_c<0>(con.attributes)).push_back(s);
                }
                else
                {
                    m_Flag = false;
                }
            }
            void decide(std::string const& s, 
//              boost::spirit::qi::unused_type ,
                context& con,
                bool& m_Flag)

            {
                if (vistrings.find(s) != nullptr)
                {
                    using boost::phoenix::at_c;
                    (fu::at_c<0>(con.attributes)).push_back(s);
                }
                else
                {
                    m_Flag = false;
                }
            }
        };



        typedef std::list<std::string> strings;
        template <typename iterator, typename Skiper = ascii::space_type>
        struct stringParser :qi::grammar <iterator, strings(), Skiper>
        {
            stringParser() : stringParser::base_type(stringslist) {
                using boost::phoenix::at_c;
                using boost::spirit::qi::_val;
                using boost::spirit::qi::int_;



                using boost::spirit::qi::omit;
                using boost::spirit::qi::lexeme;
                using boost::spirit::ascii::alpha;
                using boost::spirit::qi::raw;
                using boost::spirit::qi::fail;
                using boost::spirit::_pass;
                using boost::spirit::false_;
                using boost::spirit::qi::on_error;
                using boost::phoenix::val;
                using boost::phoenix::construct;
                using boost::phoenix::ref;
                using boost::spirit::hold;


                str_menager controler(vistrings);
                name = raw[lexeme[*alpha]];
                stringslist =
                    *(
                        omit[("VIS" > name)[ref(vistrings) += qi::_1]
                        ] |
                        //hold[
                            name
                        //] > vistrings
                       [boost::bind(&str_menager::decide, &controler, _1, _2, _3)]
                        )
                    ;
                name.name("some_name");
                stringslist.name("stringslist");
                on_error<fail>
                    (stringslist,
                        std::cout << val("Error! Expectiong ")
                        << qi::_4
                        << val(" here: \"")
                        << construct<std::string>(qi::_3, qi::_2)
                        << val("\"")
                        << std::endl);
            }
            qi::symbols<char> vistrings;
            qi::rule<iterator, strings(), ascii::space_type> stringslist;
            qi::rule<iterator, std::string(), ascii::space_type> name;



        };
    }

void TestSS()
{
    std::string str = " VIS someString someString otherString";
    typedef std::string::const_iterator iterator_type;
    typedef testParser::stringParser<iterator_type> stringParser;

    stringParser strParser;

    iterator_type end = str.end();
    iterator_type iter = str.begin();

    testParser::strings strings;
    int i = 0;
    boost::spirit::ascii::space_type sp;
    bool r = boost::spirit::qi::phrase_parse(iter, end, strParser, sp, strings);

    BOOST_FOREACH(std::string const& p, strings)
    {
        std::cout << p << "\n";
    }

    std::cout << "\n";

}

编译错误:

    Error   C2664   'void boost::_mfi::mf3<void,testParser::str_menager,const std::string &,testParser::context &,bool &>::operator ()(T *,A1,A2,A3) const': cannot convert argument 3 from 
'boost::spirit::context<boost::fusion::cons<std::list<std::string,std::allocator<_Ty>> ,boost::fusion::nil_>,boost::fusion::vector0<void>>' to
 'boost::spirit::context<boost::fusion::cons<std::list<std::string,std::allocator<_Ty>>,boost::fusion::nil>,boost::fusion::vector0<void>> ' 

我找到了一种方法来使用'hold'指令得到我想要的东西,但我不知道带有boost :: bind with context的方法代码不能编译。 我对使用凤凰的解决方案持开放态度。

1 个答案:

答案 0 :(得分:0)

查看decide成员函数的正文,您需要做四件事:

  • 属于qi::symbols<char> vistring的{​​{1}}(因此不需要是参数)。
  • str_menagerstd::string s的属性。
  • namestd::list<std::string>的属性。
  • 一个stringslist,允许您在解析时发出故障信号。

理想情况下,您的bool m_Flag成员函数应该简单:

decide

应该用:

来调用
void define(const std::string& s, std::list<std::string>& list, bool& m_Flag)
{
    if (vistrings.find(s) != nullptr)
    {
        list.push_back(s);
    }
    else
    {
        m_Flag = false;
    }
}

问题在于,由于name[adapted_decide(qi::_1,qi::_val,qi::_pass)] 是一个成员函数,凤凰函数适配宏不能直接工作(并且定义自己的decide是很多样板文件。)

One workaround could be using

phoenix::function

请注意,您需要传递4(而不是3)才能考虑是否需要传递BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,boost::mem_fn(&str_menager::decide),4); 的实例(并且在此主题上您需要使str_menager成为你的语法,因为在你的例子中,它的生命周期在构造函数完成时结束,但你尝试在那之后很久就使用它。)

以下是完整示例:(Running on Coliru

controler

PS:除非这是一个简化示例,并且您计划在#include <boost/config/warning_disable.hpp> #include <boost/spirit/include/qi.hpp> #include <boost/variant.hpp> #include <boost/spirit/include/phoenix_core.hpp> #include <boost/spirit/include/phoenix_operator.hpp> #include <boost/spirit/include/phoenix_function.hpp> #include <boost/spirit/include/phoenix_fusion.hpp> #include <boost/spirit/include/phoenix_object.hpp> #include <boost/foreach.hpp> #include <string> #include <list> #include <boost/mem_fn.hpp> namespace testParser { namespace qi = boost::spirit::qi; namespace ascii = boost::spirit::ascii; namespace sp = boost::spirit; namespace fu = boost::fusion; namespace phx = boost::phoenix; class str_menager { qi::symbols<char> const& vistrings; public: typedef void result_type; typedef void type; str_menager(qi::symbols<char> const& ss) :vistrings(ss) { } void decide(std::string const& s, std::list<std::string>& list, bool& m_Flag) { if (vistrings.find(s) != nullptr) { list.push_back(s); } else { m_Flag = false; } } }; BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,boost::mem_fn(&str_menager::decide),4);//you need to put here number_of_args+1 to take into account the instance parameter typedef std::list<std::string> strings; template <typename iterator, typename Skiper = ascii::space_type> struct stringParser :qi::grammar <iterator, strings(), Skiper> { stringParser() : stringParser::base_type(stringslist),vistrings(),controler(vistrings) { using boost::spirit::qi::omit; using boost::spirit::qi::lexeme; using boost::spirit::ascii::alpha; using boost::spirit::qi::raw; using boost::spirit::qi::fail; using boost::spirit::qi::on_error; using phx::val; using phx::ref; using phx::construct; name = raw[lexeme[*alpha]]; stringslist = *( omit[("VIS" > name)[ref(vistrings) += qi::_1] ] | name [decide_(&controler, qi::_1, qi::_val, qi::_pass)] ) ; name.name("some_name"); stringslist.name("stringslist"); on_error<fail> (stringslist, std::cout << val("Error! Expectiong ") << qi::_4 << val(" here: \"") << construct<std::string>(qi::_3, qi::_2) << val("\"") << std::endl); } qi::symbols<char> vistrings; str_menager controler; qi::rule<iterator, strings(), ascii::space_type> stringslist; qi::rule<iterator, std::string(), ascii::space_type> name; }; } void parse(const std::string& str) { typedef std::string::const_iterator iterator_type; typedef testParser::stringParser<iterator_type> stringParser; stringParser strParser; iterator_type end = str.end(); iterator_type iter = str.begin(); testParser::strings strings; boost::spirit::ascii::space_type sp; bool r = boost::spirit::qi::phrase_parse(iter, end, strParser, sp, strings); if(r) { std::cout << "Success.\n"; BOOST_FOREACH(std::string const& p, strings) { std::cout << p << "\n"; } } else { std::cout << "Something failed.\n"; } if(iter!=end) { std::cout << "Unparsed: [" << std::string(iter,end) << "]"; } std::cout << std::endl; } int main() { parse(" VIS someString someString otherString"); parse("VIS foo VIS bar foo bar baz"); parse("VIS foo bar foo VIS bar baz"); } 结构中执行更多操作,否则您只需将str_menager定义为自由函数,然后直接传递decide作为参数,即:

vistring