Reputation: 21
I am facing these below issues when I upgrade from boost_1_73 and c++14 to boost_1_77 and c++17. What will be the problem?
**Error 1:**
include/boost/utility/result_of.hpp:218:8: error: 'GB* (boost::intrusive_ptr::*)() const noexcept' is not a class, struct, or union type
**Error 2:**
include/boost/phoenix/core/detail/function_eval.hpp:119:21: error: no type named 'type' in 'struct boost::result_of<GB* (boost::intrusive_ptr::* const(boost::intrusive_ptr&))() const noexcept>'
Here is a snip of code causing the issue but can't share more code sorry.
run = qi::lit("g_d")[qi::_val = phoenix::new_<GB>()] > qi::lit("{") >
-(*iPtr)[phoenix::bind(&ECProperty::addToList,
phoenix::bind(&GBPtr::get, qi::_val), qi::_1)] >
+(&!qi::lit("}") > widthAndHeight(qi::_val)) > qi::lit("}");
Upvotes: 1
Views: 246
Reputation: 392911
Like I said, there's not enough information. Let me just use the crystal ball and assume types:
struct ECProperty {
virtual ~ECProperty() = default;
void addToList(int i) { _list.push_back(i); }
void addWH(int width, int height) { _dimensions.emplace_back(width, height); }
std::vector<int> _list;
std::vector<std::tuple<int, int> > _dimensions;
};
struct GB : ECProperty {
};
Now like I said, GBPtr
cannot be std::shared_ptr
, boost::shared_ptr
or even boost::scoped_ptr
because they lack implicit conversion (for good reason). So, we have to assume some kind of bespoke variation, let's call it DumbPointer
:
template <typename T> struct DumbPointer : public std::shared_ptr<T> {
using SP = std::shared_ptr<T>;
using SP::SP;
// A smart pointer with implicit conversion constructor... not so smart
// Don't try this at home
/*implicit*/ DumbPointer(T* take_ownership = nullptr) : SP(take_ownership)
{ }
};
using GBPtr = DumbPointer<GB>;
Okay, now we can look at the grammar. Let's assume iPtr
is really a "lazy rule" of some kind, so *iPtr
is not a parser expression using Kleene-star, but really just derefences the pointer:
auto const* iPtr = std::addressof(qi::int_);
Next, let's assume withAndHeight
is a parameterized rule (why? oh well apparently there was some reason):
qi::rule<It, void(GBPtr)> widthAndHeight;
So we can make the grammar complete and self-contained:
qi::rule<It, GBPtr(), qi::space_type> run = //
qi::lit("g_d")[qi::_val = px::new_<GB>()] > "{" //
> -(*iPtr)[ //
px::bind(&ECProperty::addToList, //
px::bind(&GBPtr::get, qi::_val),
qi::_1)] //
> +((&!qi::lit("}")) > widthAndHeight(qi::_val)) //
> qi::lit("}");
Note a few very minor simplifications.
Sidenote:
&!qi::lit
is funny, perhaps it should just have been!qi::lit
(same effect). Also, assuming thatwithAndHeight
cannot start with}
anyways, it's completely redundant anyways.Similarly,
-(*iPtr)
is just the same as*iPtr
which is why I had to assume thatiPtr
was of pointer type.
Now, the compiler error reads:
/home/sehe/custom/boost_1_77_0/boost/utility/result_of.hpp|215 col 8
error: ‘GB* (std::__shared_ptr<GB, __gnu_cxx::_S_atomic>::*)() const noexcept’ is not a class, struct, or union type
It is clear that Phoenix's result_of doesn't accept a raw pointer-to-member-function there. No doubt, the noexcept
throws it off (noexcept
didn't exist back in the day). So, let's help the compiler using std::mem_fn
:
qi::rule<It, GBPtr(), qi::space_type> run = //
qi::lit("g_d")[qi::_val = px::new_<GB>()] > "{" //
> -(*iPtr)[ //
px::bind(&ECProperty::addToList,
px::bind(std::mem_fn(&GBPtr::get), qi::_val), //
qi::_1)] //
> +((&!qi::lit("}")) > widthAndHeight(qi::_val)) //
> qi::lit("}");
Now it compiles. Good, let's imagine some useful definition of withAndHeight
:
qi::rule<It, void(GBPtr)> widthAndHeight = //
(qi::int_ >> "x" >> qi::int_)[ //
px::bind(&ECProperty::addWH,
px::bind(std::mem_fn(&GBPtr::get), qi::_r1), qi::_1,
qi::_2)];
Now we can test:
int main()
{
using It = std::string::const_iterator;
auto const* iPtr = std::addressof(qi::int_);
qi::rule<It, void(GBPtr)> widthAndHeight = //
(qi::int_ >> "x" >> qi::int_)[ //
px::bind(&ECProperty::addWH,
px::bind(std::mem_fn(&GBPtr::get), qi::_r1), qi::_1,
qi::_2)];
qi::rule<It, GBPtr(), qi::space_type> run = //
qi::lit("g_d")[qi::_val = px::new_<GB>()] > "{" //
> -(*iPtr)[ //
px::bind(&ECProperty::addToList,
px::bind(std::mem_fn(&GBPtr::get), qi::_val), //
qi::_1)] //
> +((&!qi::lit("}")) > widthAndHeight(qi::_val)) //
> qi::lit("}");
BOOST_SPIRIT_DEBUG_NODES((run)(widthAndHeight))
for (std::string const s :
{
"",
"g_d { 42 1200x800 400x768 }",
}) //
{
fmt::print("===== '{}' =====\n", s);
It f = begin(s), l = end(s);
GBPtr val;
try {
if (phrase_parse(f, l, run, qi::space, val)) {
fmt::print("Parsed _list: {} _dimensions: {}\n", val->_list,
val->_dimensions);
} else {
fmt::print("Parse failed\n");
}
} catch(qi::expectation_failure<It> const& ef) {
fmt::print(stderr, "Expected {} at '{}'\n", ef.what_,
std::string(ef.first, ef.last));
}
if (f != l) {
fmt::print("Remaining input '{}'\n", std::string(f, l));
}
}
}
Which prints Live On Compiler Explorer:
===== '' =====
Parse failed
===== 'g_d { 42 1200x800 400x768 }' =====
Parsed _list: {42} _dimensions: {(1200, 800), (400, 768)}
Perhaps you could simplify. An idea is to extract the phoenix actors:
auto const gb_ = px::bind(std::mem_fn(&GBPtr::get), _val);
qi::rule<It, GBPtr(), qi::space_type> run = //
qi::lit("g_d")[_val = px::new_<GB>()] > "{" //
> -(*iPtr)[px::bind(&ECProperty::addToList, gb_, _1)] //
> +widthAndHeight(_val) //
> "}";
Still the same output: https://compiler-explorer.com/z/ec331KW4W
However, that is a bit like turd polish. Let's embrace c++17 with polymorphic lambdas and CTAD:
px::function addWH = [](auto& ecp, int w, int h) { ecp->addWH(w, h); };
px::function addToList = [](auto& ecp, int i) { ecp->addToList(i); };
Or even better, without polymorphic lambdas:
px::function addWH = [](GB& p, int w, int h) { p.addWH(w, h); };
px::function addToList = [](GB& p, int i) { p.addToList(i); };
Now we can simply write:
qi::rule<It, void(GBPtr)> widthAndHeight = //
(qi::int_ >> "x" >> qi::int_)[addWH(*_r1, _1, _2)];
qi::rule<It, GBPtr(), qi::space_type> run = //
qi::lit("g_d")[_val = px::new_<GB>()] > "{" //
> -(*iPtr)[addToList(*_val, _1)] //
> +widthAndHeight(_val) //
> "}";
See it Live Again
Why have the inherited attribute? It complicates things:
using WandH = std::tuple<int, int>;
px::function addWH = [](GB& p, WandH wxh) { p.addWH(wxh); };
px::function addToList = [](GB& p, int i) { p.addToList(i); };
qi::rule<It, WandH()> widthAndHeight = //
qi::int_ >> "x" >> qi::int_;
qi::rule<It, GBPtr(), qi::space_type> run = //
qi::lit("g_d")[_val = px::new_<GB>()] > "{" //
> -(*iPtr)[addToList(*_val, _1)] //
> +widthAndHeight[addWH(*_val, _1)] //
> "}";
That's strictly more consistent. See it Live Again
In fact, why not just do it without any semantic action:
struct ECProperty {
std::vector<int> lst;
std::vector<WandH> dims;
};
BOOST_FUSION_ADAPT_STRUCT(ECProperty, lst, dims)
Now you can simply:
qi::rule<Iterator, WandH()> widthAndHeight = qi::int_ >> "x" >> qi::int_;
qi::rule<Iterator, ECProperty(), qi::space_type> run = qi::eps //
> "g_d" > '{' //
> qi::repeat(0, 1)[*iPtr] //
> +widthAndHeight //
> '}';
And still have the exact same output: https://compiler-explorer.com/z/3PqYMEqqP. Full listing for reference:
//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <fmt/ranges.h>
#include <fmt/ostream.h>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using WandH = std::tuple<int, int>;
struct ECProperty {
std::vector<int> lst;
std::vector<WandH> dims;
};
BOOST_FUSION_ADAPT_STRUCT(ECProperty, lst, dims)
int main()
{
using Iterator = std::string::const_iterator;
auto const* iPtr = std::addressof(qi::int_);
qi::rule<Iterator, WandH()> widthAndHeight = qi::int_ >> "x" >> qi::int_;
qi::rule<Iterator, ECProperty(), qi::space_type> run = qi::eps //
> "g_d" > '{' //
> qi::repeat(0, 1)[*iPtr] //
> +widthAndHeight //
> '}';
BOOST_SPIRIT_DEBUG_NODES((run)(widthAndHeight))
for (std::string const s :
{
"",
"g_d { 42 1200x800 400x768 }",
}) //
{
fmt::print("===== '{}' =====\n", s);
Iterator f = begin(s), l = end(s);
ECProperty val;
try {
if (phrase_parse(f, l, run, qi::space, val)) {
fmt::print("Parsed lst: {} dims: {}\n", val.lst, val.dims);
} else {
fmt::print("Parse failed\n");
}
} catch(qi::expectation_failure<Iterator> const& ef) {
fmt::print(stderr, "Expected {} at '{}'\n", ef.what_,
std::string(ef.first, ef.last));
}
if (f != l) {
fmt::print("Remaining input '{}'\n", std::string(f, l));
}
}
}
Upvotes: 0