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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.