Search code examples
c++boostboost-spirit-qiboost-phoenixboost-signals

Bind a boost signal with phoenix bind


I am using boost spirit qi to parse inbound data then dispatch the correct functionality depending on it's content.

I am using boost::signals to manage the callbacks; my problem is that I don't seem to be able to use phoenix bind with the boost signals.

Consider the following test case:

 #include <boost/signals.hpp>

 #include <boost/spirit/include/qi.hpp>
 #include <boost/spirit/include/phoenix_bind.hpp>
 #include <boost/spirit/include/phoenix_core.hpp>

 #include <iostream>

 void f(int i) {
     std::cout << i << '\n';
 }

 int main() {
     boost::signal<void(int)> sig;

     sig.connect(f);

     std::string s="123";
     auto first=s.cbegin(), last=s.cend();    

     boost::spirit::qi::parse(
         first, last,
         (
             boost::spirit::qi::int_
             [
                 boost::phoenix::bind(sig, boost::spirit::qi::_1)
             ]
         )
     ); 
 }

This doesn't compile, spitting out a wall of errors.

Note that if I replace the phoenix bind line with

boost::phoenix::bind(&f, boost::spirit::qi::_1)

it works as expected (however due to the larger design of the program this isn't possible).

Thanks in advance.


Solution

  • As noted by Igor R. in the comments, your original error was due to the fact that phoenix::bind copies its arguments by default and boost::signals are non-copyable. When you use phoenix::ref to solve that, another error emerges, this one caused by Boost.Phoenix v2's inability to find the returned type. This can also be easily solved by defining BOOST_SPIRIT_USE_PHOENIX_V3.

     #include <boost/signals.hpp>
    
     #define BOOST_SPIRIT_USE_PHOENIX_V3
     #include <boost/spirit/include/qi.hpp>
     #include <boost/spirit/include/phoenix_bind.hpp>
     #include <boost/spirit/include/phoenix_core.hpp>
    
     #include <iostream>
    
     void f(int i) {
         std::cout << i << '\n';
     }
    
     int main() {
         boost::signal<void(int)> sig;
    
         sig.connect(f);
    
         std::string s="123";
         auto first=s.cbegin(), last=s.cend();    
    
         boost::spirit::qi::parse(
             first, last,
             (
                 boost::spirit::qi::int_
                 [
                     boost::phoenix::bind(boost::phoenix::ref(sig), boost::spirit::qi::_1)
                 ]
             )
         ); 
     }