1

I'm not sure if this is related to Error when adapting a class with BOOST_FUSION_ADAPT_ADT ,but even if it is, the question behind it is still not answered/still fails see the comment of the author Error when adapting a class with BOOST_FUSION_ADAPT_ADT . (I used boost 1.69)

I have a struct

#include <string>
#include <cstdint>
namespace rtsp {
    struct request {
    };
    struct response {
        uint_fast16_t rtsp_version_major;
        uint_fast16_t rtsp_version_minor;
        uint_fast16_t status_code;
        std::string reason_phrase;
    };
    using message = boost::variant<request, response>;
}

Which I was able to use with boost::spirit::qi via

BOOST_FUSION_ADAPT_STRUCT(
        rtsp::response,
        (uint_fast16_t, rtsp_version_major)
        (uint_fast16_t, rtsp_version_minor)
        (uint_fast16_t, status_code)
        (std::string, reason_phrase)

but since I now also want to generate and not only parse the struct it, using boost::spirit::karma I have to use

BOOST_FUSION_ADAPT_ADT(
        rtsp::response,
(uint_fast16_t,const uint_fast16_t&,obj.rtsp_version_major, obj.rtsp_version_major = val)
(uint_fast16_t,const uint_fast16_t&,obj.rtsp_version_minor, obj.rtsp_version_minor = val)
(uint_fast16_t,const uint_fast16_t&,obj.status_code, obj.status_code = val)
(std::string,const std::string&,obj.reason_phrase, obj.reason_phrase = val)
)

But it explodes with several errors, from template errors up to syntax errors, for example with

In file included from /Users/markus/Entwicklung/HTW/RTSP-Streaming/src/streaming_lib/include/rtsp_request.hpp:11: In file included from /Users/markus/include/boost/spirit/include/qi.hpp:16: In file included from /Users/markus/include/boost/spirit/home/qi.hpp:14: In file included from /Users/markus/include/boost/spirit/home/qi/action.hpp:14: In file included from /Users/markus/include/boost/spirit/home/qi/action/action.hpp:16: /Users/markus/include/boost/spirit/home/qi/detail/attributes.hpp:153:9: error: ambiguous partial specializations of 'transform_attribute, unsigned short, boost::spirit::qi::domain, void>' : transform_attribute

Since it already fails at the #include <boost/spirit/include/qi.hpp> line, maybe someone knows how to correct the BOOST_FUSION_ADAPT_ADT phrase?


Whole code: /*! @file rtsp_request.hpp * */

#ifndef RTSP_GUI_RTSP_PARSER_HPP
#define RTSP_GUI_RTSP_PARSER_HPP

#include <string>
#include <cstdint>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/fusion/adapted/adt/adapt_adt.hpp>
#include <boost/spirit/include/support_adapt_adt_attributes.hpp>



namespace rtsp {
    struct request {
    };
    struct response {
        uint_fast16_t rtsp_version_major;
        uint_fast16_t rtsp_version_minor;
        uint_fast16_t status_code;
        std::string reason_phrase;
    };
    using message = boost::variant<request, response>;
}
BOOST_FUSION_ADAPT_ADT(
        rtsp::response,
(uint_fast16_t,const uint_fast16_t&,obj.rtsp_version_major, obj.rtsp_version_major = val)
(uint_fast16_t,const uint_fast16_t&,obj.rtsp_version_minor, obj.rtsp_version_minor = val)
(uint_fast16_t,const uint_fast16_t&,obj.status_code, obj.status_code = val)
(std::string,const std::string&,obj.reason_phrase, obj.reason_phrase = val)
)
/*
BOOST_FUSION_ADAPT_STRUCT(
        rtsp::response,
        (uint_fast16_t, rtsp_version_major)
        (uint_fast16_t, rtsp_version_minor)
        (uint_fast16_t, status_code)
        (std::string, reason_phrase)
)*/
namespace rtsp {

    template<typename Iterator>
    struct rtsp_response_grammar
            : ::boost::spirit::qi::grammar<Iterator, response()> {
        rtsp_response_grammar() : rtsp_response_grammar::base_type(start) {
            namespace ns = ::boost::spirit::standard;
            using ::boost::spirit::qi::uint_parser;
            using ::boost::spirit::qi::lexeme;
            using ::boost::spirit::qi::lit;
            using boost::spirit::qi::omit;
            using ::boost::spirit::qi::repeat;
            quoted_string %= lexeme['"' >> +(ns::char_ - '"') >> '"'];
            status_code = uint_parser<uint_fast16_t, 10, 3, 3>();
            at_least_one_digit = uint_parser<uint_fast16_t, 10, 1>();

            start %= lit("RTSP/") >> at_least_one_digit >> "." >> at_least_one_digit >> omit[+ns::space]
                    >> status_code >> omit[+ns::space]
                    >> *(ns::char_ - (lit("\r") | lit("\n")))
                    >> lit("\r\n");
        }

        boost::spirit::qi::rule<Iterator, std::string()> quoted_string;
        boost::spirit::qi::rule<Iterator, uint_fast16_t()> status_code;
        boost::spirit::qi::rule<Iterator, uint_fast16_t()> at_least_one_digit;
        boost::spirit::qi::rule<Iterator, response()> start;

    };

    template <typename OutputIterator>
    bool generate_response(OutputIterator sink, const response& reponse)
    {
        using ::boost::spirit::karma::lit;

        return boost::spirit::karma::generate(sink, lit("RTSP/"), reponse);
    }
}


#endif //RTSP_GUI_RTSP_PARSER_HPP
/*! @file rtsp_request.cpp
 *
 */

#include "rtsp_request.hpp"

#include <iterator>

template
struct rtsp::rtsp_response_grammar<std::string::const_iterator>;

template
bool rtsp::generate_response<std::back_insert_iterator<std::string>>(std::back_insert_iterator<std::string> sink, const response& reponse);

BTW, trying to just use the BOOST_FUSION_ADAPT_STRUCT with the karma generator function would also fail with:

In file included from /Users/markus/Entwicklung/HTW/RTSP-Streaming/src/streaming_lib/src/rtsp_request.cpp:5: In file included from /Users/markus/Entwicklung/HTW/RTSP-Streaming/src/streaming_lib/include/rtsp_request.hpp:11: In file included from /Users/markus/include/boost/spirit/include/qi.hpp:16: In file included from /Users/markus/include/boost/spirit/home/qi.hpp:14: In file included from /Users/markus/include/boost/spirit/home/qi/action.hpp:14: In file included from /Users/markus/include/boost/spirit/home/qi/action/action.hpp:14: In file included from /Users/markus/include/boost/spirit/home/qi/meta_compiler.hpp:15: In file included from /Users/markus/include/boost/spirit/home/qi/domain.hpp:18: In file included from /Users/markus/include/boost/spirit/home/support/context.hpp:18: In file included from /Users/markus/include/boost/spirit/home/support/nonterminal/expand_arg.hpp:20: /Users/markus/include/boost/spirit/home/support/string_traits.hpp:156:26: error: implicit instantiation of undefined template 'boost::spirit::traits::char_type_of' typedef typename char_type_of::type char_type; ^ /Users/markus/include/boost/spirit/home/support/string_traits.hpp:242:14: note: in instantiation of template class 'boost::spirit::traits::extract_c_string' requested here typename extract_c_string::char_type const* ^ /Users/markus/include/boost/spirit/home/karma/string/lit.hpp:180:21: note: while substituting deduced template arguments into function template 'get_c_string' [with String = rtsp::response] get_c_string( ^ /Users/markus/include/boost/spirit/home/karma/generate.hpp:69:45: note: in instantiation of function template specialization 'boost::spirit::karma::literal_string::generate

, mpl_::int_<0>, boost::spirit::unused_type>, boost::spirit::context, boost::spirit::locals >, boost::spirit::unused_type, rtsp::response>' requested here return compile(expr).generate(sink, context, unused, attr); ^ /Users/markus/include/boost/spirit/home/karma/generate.hpp:91:23: note: in instantiation of function template specialization 'boost::spirit::karma::generate , mpl_::int_<0>, boost::proto::exprns_::expr > >, 0>, rtsp::response>' requested here return karma::generate(sink, expr, attr); ^ /Users/markus/Entwicklung/HTW/RTSP-Streaming/src/streaming_lib/include/rtsp_request.hpp:69:38: note: in instantiation of function template specialization 'boost::spirit::karma::generate , boost::proto::exprns_::expr > >, 0>, rtsp::response>' requested here return boost::spirit::karma::generate(sink, lit("RTSP/"), reponse); ^ /Users/markus/include/boost/spirit/home/support/string_traits.hpp:96:12: note: template is declared here struct char_type_of; ^ /Users/markus/include/boost/spirit/home/support/string_traits.hpp:179:20: error: no matching function for call to 'call' return extract_c_string::call(str); ^~~~~~~~~~~~~~~~~~~~~~~~~ /Users/markus/include/boost/spirit/home/support/string_traits.hpp:238:42: note: in instantiation of member function 'boost::spirit::traits::extract_c_string::call' requested here return extract_c_string::call(str); ^ /Users/markus/include/boost/spirit/home/karma/string/lit.hpp:180:21: note: in instantiation of function template specialization 'boost::spirit::traits::get_c_string' requested here get_c_string( ^ /Users/markus/include/boost/spirit/home/karma/generate.hpp:69:45: note: in instantiation of function template specialization 'boost::spirit::karma::literal_string::generate , mpl_::int_<0>, boost::spirit::unused_type>, boost::spirit::context, boost::spirit::locals >, boost::spirit::unused_type, rtsp::response>' requested here return compile(expr).generate(sink, context, unused, attr); ^ /Users/markus/include/boost/spirit/home/karma/generate.hpp:91:23: note: in instantiation of function template specialization 'boost::spirit::karma::generate , mpl_::int_<0>, boost::proto::exprns_::expr > >, 0>, rtsp::response>' requested here return karma::generate(sink, expr, attr); ^ /Users/markus/Entwicklung/HTW/RTSP-Streaming/src/streaming_lib/include/rtsp_request.hpp:69:38: note: in instantiation of function template specialization 'boost::spirit::karma::generate , boost::proto::exprns_::expr > >, 0>, rtsp::response>' requested here return boost::spirit::karma::generate(sink, lit("RTSP/"), reponse); ^ /Users/markus/include/boost/spirit/home/support/string_traits.hpp:159:25: note: candidate template ignored: could not match 'T ' against 'rtsp::response' static T const call (T* str) ^ /Users/markus/include/boost/spirit/home/support/string_traits.hpp:165:25: note: candidate template ignored: could not match 'const T ' against 'rtsp::response' static T const call (T const* str)

Superlokkus
  • 4,731
  • 1
  • 25
  • 57
  • ADAPT_ADT has a rather broad tendency to explode. The proxies it uses are a leaky abstraction and they can easily trigger UB when used in "surprising" contexts. – sehe Sep 07 '18 at 14:59
  • 1
    So your pragmatic advise is to not use the fusion abstraction in karma until, spirit manages to get loose from fusion? – Superlokkus Sep 07 '18 at 15:00
  • Side note, why do not you use `BOOST_FUSION_ADAPT_STRUCT`? – Nikita Kniazev Sep 07 '18 at 15:01
  • @NikitaKniazev I can't since it also generates errors, when instantiating the karma generator function `rtsp::generate_response ` with a back_inserter iterator for a `std::string`: ... /Users/markus/include/boost/spirit/home/support/string_traits.hpp:156:26: error: implicit instantiation of undefined template 'boost::spirit::traits::char_type_of' typedef typename char_type_of::type char_type; – Superlokkus Sep 07 '18 at 15:15
  • I do not see problems in Spirit https://wandbox.org/permlink/QYstdTcPZNwABt3w and your Karma generator expression `generate(sink, lit("RTSP/"), reponse)` clearly does not match with the struct definition. – Nikita Kniazev Sep 07 '18 at 15:31
  • @NikitaKniazev Oh I'm sorry I was thinking that generate expression should always succeed no matter of the struct definition. I will change it accordingly, at get back to you/this question (either delete it and give you a comment at github or modify it and give you a comment at github). I'm sorry. – Superlokkus Sep 07 '18 at 15:34
  • To be completely clear: Fusion Adaptation is fine. Just ADT-proxies are often inviting problems. Also, they can be indicative of abstraction-levels confusion, though this apply more on the Qi side (where my experience lies) than the Karma side – sehe Sep 07 '18 at 15:48
  • @sehe do you have examples? Qi and Karma should support ADT out-of-the-box without problems. – Nikita Kniazev Sep 07 '18 at 15:55
  • @NikitaKniazev I feel we might have had this conversation before. I'm sure when I encountered them I have brought it up on the mailing list. And they're usually here on site because ... well you know, that's how I usually find them. – sehe Sep 07 '18 at 15:57
  • I am sorry, I do not read the general mail list because it has a lot of traffic and unfriendly in usage and devel list has no activity, but I am sure that the right place for bugs is the issue tracker. – Nikita Kniazev Sep 07 '18 at 16:11
  • @NikitaKniazev they are once it is clear there are bugs. I'd appreciate if you stopped subtly criticizing my perceived lack of contribution. We all have our preferences. Like you I'm doing my part. We both go far beyond what is required of us (which is, literally nothing :)) – sehe Sep 07 '18 at 16:15
  • @sehe I highly value your contribution and your support for folks around spirit, no doubt. However at he point when you gave the suggestion not to use ADT because it has problems I thought you know some unfixed bugs otherwise you mislead people (and this is the worst thing that can happen). "We both go far beyond what is required of us (which is, literally nothing :))" - that's true. Anyway, sorry for bothering. – Nikita Kniazev Sep 07 '18 at 16:31
  • 1
    @NikitaKniazev fair enough. I'll still give that recommendation even if I'm absolutely sure all bugs have gone. And that's just because of professional experience: one rarely needs the complexity and it's avoidable. (Like I hinted before, I find that "requiring" ADT adaptation is frequently a code smell of too much responsibility on 1 class - mixing levels of abstraction viewed another way. Of course, it might be desired for an optimization, but I'd rarely suggest rolling a Qi parser in such cases). Cheers! – sehe Sep 07 '18 at 16:43

1 Answers1

2

A well defined grammar handles either BOOST_FUSION_ADAPT_STRUCT or BOOST_FUSION_ADAPT_ADT without problems.

Example:

namespace rtsp {
    ...

    template <typename OutputIterator>
    bool generate_response(OutputIterator sink, const response& reponse)
    {
        using ::boost::spirit::karma::lit;
        using ::boost::spirit::karma::uint_;
        using ::boost::spirit::karma::string;

        return boost::spirit::karma::generate(sink,
            lit("RTSP/") << uint_ << "." << uint_ << " " << uint_ << " " << string
          , reponse);
    }
}

int main()
{
    std::string s;
    generate_response(std::back_inserter(s), rtsp::response{ 1, 0, 200, "OK" });
    std::cout << s;
}

Prints: RTSP/1.0 200 OK

Update: Qi bug involving BOOST_FUSION_ADAPT_ADT confirmed and reported.

Nikita Kniazev
  • 3,728
  • 2
  • 16
  • 30
  • No explanation why it fails if the attribute is omitted from the generator though – sehe Sep 07 '18 at 15:46
  • I am not sure I understand you. The attribute is not omitted in the question, and it is simply does not match to the generator, however the error message might be more user-friendly in this case. – Nikita Kniazev Sep 07 '18 at 15:52
  • Yes it works with `BOOST_FUSION_ADAPT_STRUCT` but not with `BOOST_FUSION_ADAPT_ADT` on my machine with different errors when ever `#include ` is included or not (either error: ambiguous partial specializations of 'transform_attribute – Superlokkus Sep 07 '18 at 15:54
  • I guess I was looking in at it backwards. `qi::rule x = qi::int_;` would be fine (but indeed, the problem is not comparable, because it would be more analog to `qi::parse(f,l,x,some_variable)` indeed). Please disregard my comment – sehe Sep 07 '18 at 15:55
  • As I said in the answer, it works with `BOOST_FUSION_ADAPT_ADT` without any problem https://wandbox.org/permlink/ruhlrayEqgD4rf2h – Nikita Kniazev Sep 07 '18 at 16:02
  • @NikitaKniazev It fails with `BOOST_FUSION_ADAPT_ADT` when I add the 2 explicit template from the .cpp are used, like added in line 79 in your wandbox, see https://wandbox.org/permlink/w7RLrUcoK8SJSXcn Of course I'm not sure if this is just because I'm making a mistake in my explicit instantiation expression, but the errors are making me think of the probability 50%/50%. – Superlokkus Sep 07 '18 at 22:01
  • And I just checked: It breaks also without the explicit qi parser/rtsp::response_grammar instantiation, but then in my boost::test case translation unit, where I test the qi parser. – Superlokkus Sep 07 '18 at 22:14
  • Well, this ambiguity is a real bug, it is triggered by `status_code`/`at_least_one_digit` usage. However after that at dealing with containers you will encounter the limitation of spirit when proxy does not return a reference to the actual object. – Nikita Kniazev Sep 07 '18 at 23:57