i使用VC14,而Boost版本为1.60。
#include <boost/config/warning_disable.hpp>
#include <boostspirithomeqi.hpp>
#include <boostvariant.hpp>
#include <boostspiritincludeqi.hpp>
#include <boostspiritincludephoenix_core.hpp>
#include <boostspiritincludephoenix_operator.hpp>
#include <boostspiritincludephoenix_object.hpp>
#include <boost/phoenix/function/adapt_function.hpp>
#include <boostspiritincludephoenix_fusion.hpp>
#include <boostforeach.hpp>
#include <string>
#include <list>
#include <boostbind.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的代码不会编译。我使用凤凰使用的解决方案开放。
查看decide
成员功能的正文您需要四件事:
- 属于
str_menager
的qi::symbols<char> vistring
(因此不需要是参数)。 -
std::string s
是name
的属性。 -
std::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
是成员函数,因此Phoenix函数适应宏无法直接工作(并且定义您自己的phoenix::function
是很多样板)。
一个解决方法可以使用:
BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,boost::mem_fn(&str_menager::decide),4);
请注意,您需要通过4(不是3),以考虑到还需要通过str_menager
实例(在此主题上,您需要将controler
作为语法成员,因为在您的示例中终生结束后,构造函数完成了,但在此之后您尝试使用它)。
这是一个完整的示例:(在Coliru上运行)
#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");
}
p.s。:除非这是一个简化的示例,并且您计划在str_menager
struct中进行更多操作,否则您可以简单地将decide
定义为免费函数,然后将vistring
直接传递为参数,即:
void decide(const qi::symbols<char>& vistring, const std::string& s, std::list<std::string>& list, bool& m_Flag)
{
//same as before
}
BOOST_PHOENIX_ADAPT_FUNCTION(void,decide_,decide,4);
...
name[decide_(phx::ref(vistring),qi::_1,qi::_val,qi::_pass)]
...