Search code examples
boostc++11enumsboost-spiritboost-spirit-qi

Boost Spirit debug enum class (c++11) compile error


I am trying to debug a simple struct which contains an enum class with BOOST_SPIRIT_DEBUG_NODE, but I always get the compile error "C:\boost\boost\spirit\home\support\attributes.hpp:1226: error: cannot bind 'std::basic_ostream' lvalue to 'std::basic_ostream&&' near 'out << val;'"

I don't know why I get a rvalue error like that, I tried to to add a manual overload for the operator<< for the enum class but that didn't work either.

I am using boost 1.55 and try to compile with gcc 4.8 with MinGW 32-bit on Windows 8.1 x64.

When I change the enum class to a default c++ enum it works, but I'd like to use the new enum classes for proper namespace handling.


Solution

  • I don't know why I get a rvalue error like that, I tried to to add a manual overload for the operator<< for the enum class but that didn't work either.

    I think that required code, since that does work:

    1. First, with a classic enum Live on Coliru

      #define BOOST_SPIRIT_DEBUG
      #include <boost/spirit/include/qi.hpp>
      #include <iostream>
      
      namespace qi    = boost::spirit::qi;
      
      struct data_t
      {
          std::string label;
          enum Choice { left, right, up, down } choice;
      
          data_t(std::string label="default", Choice choice=left): label(std::move(label)), choice(choice) {}
      
          friend std::ostream& operator<<(std::ostream& os, Choice const& v) {
              switch(v) { 
                  case left: return os << "left";
                  case right:return os << "right";
                  case up:   return os << "up";
                  case down: return os << "down";
                  default:   return os << "?";
              }
          }
          friend std::ostream& operator<<(std::ostream& os, data_t const& v) {
              return os << "{label:" << v.label << ";choice:" << v.choice << "}";
          }
      };
      
      
      template <typename It, typename Skipper = qi::space_type>
          struct parser : qi::grammar<It, data_t(), Skipper>
      {
          parser() : parser::base_type(start)
          {
              using namespace qi;
      
              choice_.add
                  ("left",  data_t::left)
                  ("right", data_t::right)
                  ("up",    data_t::up)
                  ("down",  data_t::down);
      
              start %= as_string[ lexeme[+graph] ] >> lexeme [choice_];
      
              BOOST_SPIRIT_DEBUG_NODE(start);
          }
      
      private:
          qi::symbols<char, data_t::Choice> choice_;
          qi::rule<It, data_t(), Skipper> start;
      };
      
      bool doParse(const std::string& input)
      {
          typedef std::string::const_iterator It;
          auto f(begin(input)), l(end(input));
      
          parser<It, qi::space_type> p;
          data_t data;
      
          try
          {
              bool ok = qi::phrase_parse(f,l,p,qi::space,data);
              if (ok)   
              {
                  std::cout << "parse success\n";
                  std::cout << "data: " << data << "\n";
              }
              else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
      
              if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\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;
      }
      
      int main()
      {
          bool ok = doParse("label1 up");
          return ok? 0 : 255;
      }
      
    2. Second with an enum class Live on Coliru

      #define BOOST_SPIRIT_DEBUG
      #include <boost/spirit/include/qi.hpp>
      #include <iostream>
      
      namespace qi    = boost::spirit::qi;
      
      struct data_t
      {
          std::string label;
          enum class Choice { left, right, up, down } choice;
      
          data_t(std::string label="default", Choice choice=Choice::left): label(std::move(label)), choice(choice) {}
      
          friend std::ostream& operator<<(std::ostream& os, Choice const& v) {
              switch(v) { 
                  case Choice::left: return os << "left";
                  case Choice::right:return os << "right";
                  case Choice::up:   return os << "up";
                  case Choice::down: return os << "down";
                  default:   return os << "?";
              }
          }
          friend std::ostream& operator<<(std::ostream& os, data_t const& v) {
              return os << "{label:" << v.label << ";choice:" << v.choice << "}";
          }
      };
      
      
      template <typename It, typename Skipper = qi::space_type>
          struct parser : qi::grammar<It, data_t(), Skipper>
      {
          parser() : parser::base_type(start)
          {
              using namespace qi;
      
              choice_.add
                  ("left",  data_t::Choice::left)
                  ("right", data_t::Choice::right)
                  ("up",    data_t::Choice::up)
                  ("down",  data_t::Choice::down);
      
              start %= as_string[ lexeme[+graph] ] >> lexeme [choice_];
      
              BOOST_SPIRIT_DEBUG_NODE(start);
          }
      
      private:
          qi::symbols<char, data_t::Choice> choice_;
          qi::rule<It, data_t(), Skipper> start;
      };
      
      bool doParse(const std::string& input)
      {
          typedef std::string::const_iterator It;
          auto f(begin(input)), l(end(input));
      
          parser<It, qi::space_type> p;
          data_t data;
      
          try
          {
              bool ok = qi::phrase_parse(f,l,p,qi::space,data);
              if (ok)   
              {
                  std::cout << "parse success\n";
                  std::cout << "data: " << data << "\n";
              }
              else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
      
              if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\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;
      }
      
      int main()
      {
          bool ok = doParse("label1 up");
          return ok? 0 : 255;
      }
      

    My guess is you forgot to add serialization to either your enum or your struct.