Re: [Qi] Bizarro Qi results coming from compiler
Michael Powell <[email protected]>
| Newsgroups | gmane.comp.parsers.spirit.general |
|---|---|
| Message-ID | <CAMEoF_ECcK=U13H2RadVKOqbskVgXPoJmfaRYXqQ2j4LwMUtrA@mail.gmail.com> |
On Wed, Nov 29, 2017 at 1:31 PM, Michael Powell <[email protected]> wrote: > I am receiving bizarro error coming from Spirit (latest stable Boost > release, Visual Studio 2015, but also via Coliru, and Wandbox, gcc). When I write in terms of a template function instead of an ad-hoc lambda, I get compiler success. I don't know what's going on with that, except that something seems to be getting shaved off of the type system when the reference gets captured by the lambda. namespace client { template<class Expr, typename Attribute> void verify_grammar(std::string const& s, Attribute const& a, bool parsed_expected) { using namespace boost::spirit::qi; auto it = s.begin(); Expr g; Attribute b; auto const parsed_actual = phrase_parse(it, s.end(), g, Expr::skipper_type(), b); // I can even utilize the derived skipper_type ^^^^^^^^^^^^^^^^^^^^^ REQUIRE(parsed_actual == parsed_expected); if (parsed_expected) { REQUIRE(it == s.end()); // Catch unit testing REQUIRE(b == a); } else { REQUIRE(it != s.end()); } } } > Severity Code Description Project File Line Suppression State > Error C2664 'bool boost::function4<R,T0,T1,T2,T3>::operator > ()(T0,T1,T2,T3) const': cannot convert argument 4 from 'const > skipper_type' to 'const boost::spirit::qi::reference<const > boost::spirit::qi::rule<Iterator,T1,T2,T3,T4>> &' > Rfc3986_Uri_RegexSyntaxVerification > G:\Source\Boost.Installs\boost_1_65_1\boost\spirit\home\qi\nonterminal\rule.hpp > 304 > > // ... > > template<typename Iterator> > struct my_skipper : qi::grammar<Iterator> { > > qi::rule<Iterator> _skip; > > my_skipper() : my_skipper::base_type(_skip) { > using namespace boost::spirit::qi; > _skip = ascii::space; > } > }; > > template<typename Iterator, typename Skipper = my_skipper<Iterator>> > struct my_port : qi::grammar<Iterator, std::uint16_t(), Skipper> { > > qi::rule<Iterator, std::uint16_t(), Skipper> _start; > > my_port() : my_port::base_type(_start), _start() { > > using std::uint16_t; > using qi::uint_parser; > using qi::lexeme; > > _start = lexeme[uint_parser<uint16_t, 10, 1, 5>()]; > } > }; > > // ... > > my_port<std::string::const_iterator> port_g_; > > auto& space_ = boost::spirit::qi::ascii::space; > > auto const& parse_port_ = [&port_g_, &space_](std::string const& s, > std::uint16_t const& y, bool expected_parsed) { > auto it = s.begin(); > std::uint16_t x; > auto const actual_parsed = phrase_parse(it, s.end(), port_g_, space_, x); > }; > > parse_port_("12345", 12345, true); > parse_port_("abc", -1, false); > > I followed through on the reasons given here, but it just does not hold water. > > https://stackoverflow.com/questions/21672316/boost-spirit-skipper-compile-time-error > > Particularly the idiotic comments concerning: > > // If you are seeing a compilation error here stating that the > // fourth parameter can't be converted to a required target type > // then you are probably trying to use a rule or a grammar with > // an incompatible skipper type. > if (f(first, last, context, skipper)) > > I assure you, I ***have*** set the skipper, and it **DOES NOT WORK** > with parse_phrase, and I'm not sure as to **WHY**. > > Can someone shed some light on this? Should I be skipping at all? How > does something like this work in my production grammar, and not now > that I am trying to vet a more complex issue, starting from this > "simple" one? Which, from what I can tell, is effectively the same as > the one I've already tested in my production code? > > template<typename Iterator, typename Skipper = > boost::spirit::qi::ascii::space_type> > struct PortParser : boost::spirit::qi::grammar<Iterator, > std::uint16_t(), Skipper> { > > boost::spirit::qi::rule<Iterator, std::uint16_t(), Skipper> _start; > > PortParser() : PortParser::base_type(_start), _start() { > > using std::string; > using std::uint16_t; > using std::numeric_limits; > using boost::lexical_cast; > using boost::spirit::qi::lexeme; > using boost::spirit::qi::uint_parser; > > _start = lexeme[uint_parser<uint16_t, 10, 1, 5>()]; > > typedef numeric_limits<uint16_t> Limits; > > _start.name("a valid port number from " > + lexical_cast<string>(Limits::min()) > + " through " + lexical_cast<string>(Limits::max())); > } > }; > > It just doesn't make sense to me. > > Cheers, > > Michael Powell ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot