boost spirit qi _error通过引用传递errorhandler结构
boost spirit qi on_error pass error_handler struct by reference
我还有一个灵气的拦截器问题。
我在一个名为error_handler的函数结构中实现了错误处理。这是通过引用传递给语法构造函数的(参见Qi的MiniC示例)。
然后,我在语法的构造函数中定义了on_error<fail>
typedef boost::phoenix::function<error_handler<> > error_handler_function;
on_error<fail>(gr_instruction,
error_handler_function(err_handler)(L"Error: Expecting ", _4, _3));
// more on_error<fail>s...
但是,我的error_handler
有私人成员。似乎每次调用on_error
时,都会复制err_handler
对象,因此一旦函子离开,更改的局部变量就会被销毁。
我尝试通过引用传递处理程序:
typedef boost::phoenix::function<error_handler<>& > error_handler_function; // <--- Note the ampersand!
on_error<fail>(gr_instruction,
error_handler_function(err_handler)(L"Error: Expecting ", _4, _3));
// more on_error<fail>s...
然而,问题仍然存在:on_error()
在err_handler
的副本上工作,而不是一个实例!!
我也尝试过boost::phoenix::ref(err_handler)
的变体,除了编译错误什么都没有。
当然,必须有一个简单的解决方案来通过引用传递处理程序?
如有任何意见,我将不胜感激。谢谢你的帮助。
是,phx::bind和phx::function<>默认情况下将按值获取它们的包装可调用项。然而
假设[1],您有一个这样的错误处理程序。。。极简主义的例子:
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "n";
}
mutable int proof = 0;
};
(正如你所看到的,我明确地使它不可复制,以确保编译器不会在我背后默默地生成代码。)
现在,我不确定这是否是你意外错过的组合,但是:
on_error<fail>(function, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(start, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
效果很好,也是
auto ll = phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3);
on_error<fail>(function, ll);
on_error<fail>(start, ll);
on_error<fail>(gr_instruction, ll);
注意,由于bind
引用,我们需要确保err_handler
的生存期与解析器的生存期匹配(或超过),所以我将err_handler
作为解析器类的成员。
当我将其输入传递给失败时,我的程序将能够打印my_error_handler
:调用的proof
std::cout << "The 'proof' in the err_handler instance is: " << p.err_handler.proof << "n";
一如既往,一个完全集成的示例程序:
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace asmast
{
typedef std::string label;
}
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "n";
}
mutable int proof = 0;
};
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Skipper>
{
parser() :
parser::base_type(start)
{
using namespace qi;
start = lexeme["Func" >> !(alnum | '_')] > function;
function = gr_identifier
>> "{"
>> -(
gr_instruction
| gr_label
//| gr_vardecl
//| gr_paramdecl
) % eol
> "}";
gr_instruction_names.add("Mov", unused);
gr_instruction_names.add("Push", unused);
gr_instruction_names.add("Exit", unused);
gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
gr_operands = -(gr_operand % ',');
gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [ '"' >> *("""" | ~char_(""")) >> '"' ];
gr_newline = +( char_('r')
|char_('n')
);
gr_label = gr_identifier >> ':' > gr_newline;
#if 1
on_error<fail>(function, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(start, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
#else
auto ll = phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3);
on_error<fail>(function, ll);
on_error<fail>(start, ll);
on_error<fail>(gr_instruction, ll);
#endif
// more on_error<fail>s...
BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
my_error_handler<> err_handler;
private:
qi::symbols<char, qi::unused_type> gr_instruction_names;
qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
qi::rule<It, qi::unused_type()> gr_newline;
qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
};
int main()
{
typedef boost::spirit::istream_iterator It;
std::cin.unsetf(std::ios::skipws);
It f(std::cin), l;
parser<It, qi::blank_type> p;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank);
if (ok) std::cout << "parse successn";
else std::cerr << "parse failed: '" << std::string(f,l) << "'n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'n";
std::cout << "The 'proof' in the err_handler instance is: " << p.err_handler.proof << "n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'n";
}
return false;
}
当输入时
Func Ident{
Mov name, "hello"
Push 5
Exit
}
它打印(作为第一行/最后一行)
my_error_handler invoked 0
my_error_handler invoked 1
...
The 'proof' in the err_handler instance is: 2
[1]这不是我第一次想象相关代码
我记得我对这件事考虑得很晚,想检查一下:
当然,
my_error_handler<> err_handler;
phx::function<my_error_handler<> > err_handler_(err_handler);
会起作用(但尝试复制err_handler
实例,这不是您想要的)。现在,
phx::function<my_error_handler<> > err_handler_(phx::ref(err_handler));
不会飞起来(因为my_error<>
不能从phx::ref(err_handler)
构建),所以从逻辑上讲,你实际上需要做的只是:
namespace P = boost::proto;
phx::function<const phx::actor<P::exprns_::basic_expr<
P::tagns_::tag::terminal,
P::argsns_::term<boost::reference_wrapper<my_error_handler<> > >,
0l>
> > err_handler_;
哪个。。。与phx::bind
完全一样,但具有更多的语法优势:
on_error<fail>(function, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(start, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, err_handler_(L"Error: Expecting ", _4, _3));
现在,使用一些C++11,这可以写得稍微不那么冗长:
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
查看它的工作情况使用以下代码在Coliru上直播:
#define BOOST_SPIRIT_USE_PHOENIX_V3
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace asmast
{
typedef std::string label;
}
template <typename=void> struct my_error_handler {
my_error_handler() = default;
my_error_handler(my_error_handler const&) = delete;
template<typename...> struct result { typedef void type; };
template<typename... T> void operator()(T&&...) const {
std::cerr << "my_error_handler invoked " << proof++ << "n";
}
mutable int proof = 0;
};
template <typename It, typename Skipper = qi::blank_type>
struct parser : qi::grammar<It, Skipper>
{
parser() :
parser::base_type(start),
err_handler(),
err_handler_(phx::ref(err_handler))
{
using namespace qi;
start = lexeme["Func" >> !(alnum | '_')] > function;
function = gr_identifier
>> "{"
>> -(
gr_instruction
| gr_label
//| gr_vardecl
//| gr_paramdecl
) % eol
> "}";
gr_instruction_names.add("Mov", unused);
gr_instruction_names.add("Push", unused);
gr_instruction_names.add("Exit", unused);
gr_instruction = lexeme [ gr_instruction_names >> !(alnum|"_") ] > gr_operands;
gr_operands = -(gr_operand % ',');
gr_identifier = lexeme [ alpha >> *(alnum | '_') ];
gr_operand = gr_identifier | gr_string;
gr_string = lexeme [ '"' >> *("""" | ~char_(""")) >> '"' ];
gr_newline = +( char_('r')
|char_('n')
);
gr_label = gr_identifier >> ':' > gr_newline;
#if 0
on_error<fail>(function, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(start, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, phx::bind(phx::ref(err_handler), L"Error: Expecting ", _4, _3));
#else
on_error<fail>(function, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(start, err_handler_(L"Error: Expecting ", _4, _3));
on_error<fail>(gr_instruction, err_handler_(L"Error: Expecting ", _4, _3));
#endif
// more on_error<fail>s...
BOOST_SPIRIT_DEBUG_NODES((start)(function)(gr_instruction)(gr_operands)(gr_identifier)(gr_operand)(gr_string));
}
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
private:
qi::symbols<char, qi::unused_type> gr_instruction_names;
qi::rule<It, Skipper> start, function, gr_instruction, gr_operands, gr_operand, gr_string;
qi::rule<It, qi::unused_type()> gr_newline;
qi::rule<It, asmast::label(), Skipper> gr_label, gr_identifier;
};
int main()
{
typedef boost::spirit::istream_iterator It;
std::cin.unsetf(std::ios::skipws);
It f(std::cin), l;
parser<It, qi::blank_type> p;
try
{
bool ok = qi::phrase_parse(f,l,p,qi::blank);
if (ok) std::cout << "parse successn";
else std::cerr << "parse failed: '" << std::string(f,l) << "'n";
if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'n";
std::cout << "The 'proof' in the err_handler instance is: " << p.err_handler.proof << "n";
return ok;
} catch(const qi::expectation_failure<It>& e)
{
std::string frag(e.first, e.last);
std::cerr << e.what() << "'" << frag << "'n";
}
return false;
}
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- boost spirit qi _error通过引用传递errorhandler结构