C++ 通过引用在\u错误传递错误\u处理程序结构上提升精神气

C++ 通过引用在\u错误传递错误\u处理程序结构上提升精神气,c++,reference,boost-spirit,boost-spirit-qi,boost-phoenix,C++,Reference,Boost Spirit,Boost Spirit Qi,Boost Phoenix,我还有另一个关于灵气的拦截器问题 我已经在名为error\u handler的函子结构中实现了错误处理。 通过引用将其传递给语法构造函数(参见Qi的MiniC示例) 然后,我在语法的构造函数中定义了关于错误的: typedef boost::phoenix::function<error_handler<> > error_handler_function; on_error<fail>(gr_instruction, error_handle

我还有另一个关于灵气的拦截器问题

我已经在名为error\u handler的函子结构中实现了错误处理。 通过引用将其传递给语法构造函数(参见Qi的MiniC示例)

然后,我在语法的构造函数中定义了关于错误的

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...
但是,问题仍然存在:
on_error()
可用于
err_handler
的副本,而不是单个实例

我还尝试了
boost::phoenix::ref(err\u 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;
};
与往常一样,一个完全集成的示例程序:

#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 success\n";
        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;
}
它打印(作为第一行/最后一行)



[1]这不是我第一次想象相关的代码了

我记得当时有一个很晚的想法,想检查一下:

当然,

my_error_handler<> err_handler;
phx::function<my_error_handler<> > err_handler_(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_;
现在,使用一些C++11,可以编写稍微不那么冗长的代码:

my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
我的错误处理程序错误处理程序;
phx::函数err\u handler\u;

请参见使用下面的代码运行它:

#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 success\n";
        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;
}
#定义提升(精神)使用(凤凰)
//#定义BOOST_SPIRIT_调试
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间phx=boost::phoenix;
名称空间asmast
{
typedef std::字符串标签;
}
模板结构我的错误处理程序{
my_error_handler()=默认值;
我的错误处理程序(我的错误处理程序常量&)=删除;
模板结构结果{typedef void type;};
模板无效运算符()(T&…)常量{
std::cerr函数;
函数=gr\U标识符
>> "{"
>> -(
gr_指令
|gr_标签
//|格鲁·瓦尔德克尔
//|gr_paramdecl
)%eol
> "}";
gr_指令_名称。添加(“Mov”,未使用);
gr_指令_名称。添加(“推”,未使用);
gr_指令_名称。添加(“退出”,未使用);
gr|U指令=词素[gr|U指令名称>>!(alnum |“”)]>gr|U操作数;
gr_操作数=-(gr_操作数%',');
gr|U identifier=lexeme[alpha>>*(alnum |'"');
gr_操作数=gr_标识符| gr_字符串;
gr_string=lexeme[''''>>*(“\'\'\'\'\'\'\'.\char\'\')>'''];
gr_换行符=+(字符('\r'))
|字符('\n')
);
gr_标签=gr_标识符>>':'>gr_换行符;
#如果0
on_error(函数,phx::bind(phx::ref(err_handler),L“error:Expecting”,_4,_3));
on_error(start,phx::bind(phx::ref(err_handler),L“error:Expecting”,_4,_3));
on_error(gr_指令,phx::bind(phx::ref(err_handler),L“error:Expecting”,_4,_3));
#否则
on_error(函数,err_handler(L“error:Expecting”,_4,_3));
on_错误(开始,错误处理程序(错误:预期的),错误4,错误3);
on_error(gr_指令,err_处理程序(error:Expecting),_4,_3));
#恩迪夫
//更多关于你的错误。。。
BOOST_-SPIRIT_-DEBUG_节点((启动)(函数)(gr_指令)(gr_操作数)(gr_标识符)(gr_操作数)(gr_字符串));
}
我的错误处理程序错误处理程序;
phx::函数err\u handler\u;
私人:
qi::符号gr_指令_名称;
qi::规则开始、函数、gr_指令、gr_操作数、gr_操作数、gr_字符串;
qi::规则gr_新行;
qi::规则gr_标签,gr_标识符;
};
int main()
{
typedef boost::spirit::istream_迭代器It;
std::cin.unsetf(std::ios::skipws);
它是f(标准::cin),l;
语法分析器p;
尝试
{
bool ok=qi::短语解析(f,l,p,qi::blank);

如果(确定)std::非常感谢您的回复和示例。我将在早上的第一件事中尝试。您在前面的示例的基础上继续构建有点可笑:]Spirit确实是一条陡峭的学习曲线;特别是由于它高度依赖于其他boost库,并且很难解码编译器错误,但最终非常值得。再次感谢感谢您的耐心!@namezero Lol。我只是为了节约!我不喜欢从头开始输入随机代码样本:/另外,要小心那里的意见偏见。我得出的结论是,手摇解析器有时更可取。然而,一旦掌握了窍门,Spirit……对于快速原型来说是无法忍受的(并且不喜欢使用Antlr/CoCo/…)。谢谢,这确实有效!我没有偶然发现使用phoenix::bind的示例。至于[1],错误处理程序就像MiniC示例中的一样,只是我没有输出到std::cout。我知道在这个解析器中不使用Spirit会更容易,但是我们遇到了更复杂的问题,所以我认为这将是开始理解库的一个很好的方法。再次感谢!@namezero我并不真正关心sa我必须查找的示例。至少,你说它是有状态的。所以我写了我能想到的最简单的有状态函子:)我刚刚意识到,
phx::function
是你的
phx::function
思想的明显替代品。见我的新答案。+1.我认为你也可以使用
phx::function:type>err\u handler\uu;
。我想我更喜欢简单地把
proof
作为初始参考在构造器中进行了优化,但这种方式非常有趣。
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
my_error_handler<> err_handler;
phx::function<my_error_handler<> > err_handler_(err_handler);
phx::function<my_error_handler<> > err_handler_(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_;
    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));
my_error_handler<> err_handler;
phx::function<decltype(phx::ref(err_handler))> err_handler_;
#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 success\n";
        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;
}