1
votes

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)

1
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
So your pragmatic advise is to not use the fusion abstraction in karma until, spirit manages to get loose from fusion?Superlokkus
Side note, why do not you use BOOST_FUSION_ADAPT_STRUCT?Nikita Kniazev
@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<rtsp::response>' typedef typename char_type_of<String>::type char_type;Superlokkus
@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

1 Answers

2
votes

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.