Related
This code is not my actual code, but just illustrates the issue. I have a rule that matches 0 or more digits, and an action that is supposed to count them and return that count as the synthesized attribute.
The attribute of *qi::ascii::digit should be a std::vector of the matched digits. So, I wrote the action so that it simply calls .size() and assigns the result to the synthesized attribute. To call .size(), I use boost.phoenix to bind a lambda that calls .size().
#include <boost/phoenix/bind/bind_function_object.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/spirit/include/qi.hpp>
#include <cstdint>
#include <iostream>
#include <string>
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
using It = std::string::iterator;
struct Parser : qi::grammar<std::string::iterator, size_t()> {
Parser() : Parser::base_type(r) {
auto count = [](auto&& v) { return v.size(); };
r %= (*qi::ascii::digit)[qi::_val = phx::bind(count, qi::_1)];
}
qi::rule<It, size_t()> r;
};
int main() {
using namespace std;
std::string s = "123";
int c;
Parser p;
qi::parse(s.begin(), s.end(), p, c);
std::cout << c << '\n';
}
But it doesn't work. I expect this code to compile and print 3. Instead, I get a very long compile error. The error is roughly what I would expect if the action were simply qi::_val = qi::_1, which perplexes me.
In file included from /usr/local/include/boost/type_traits/is_convertible.hpp:20,
from /usr/local/include/boost/type_traits/is_empty.hpp:12,
from /usr/local/include/boost/mpl/empty_base.hpp:23,
from /usr/local/include/boost/fusion/sequence/intrinsic/at.hpp:15,
from /usr/local/include/boost/phoenix/core/expression.hpp:11,
from /usr/local/include/boost/phoenix/bind/bind_function_object.hpp:17,
from spirit2.cpp:1:
/usr/local/include/boost/spirit/home/qi/parse.hpp: In instantiation of ‘bool boost::spirit::qi::parse(Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Expr = int; Attr = Parser]’:
/usr/local/include/boost/spirit/home/qi/parse.hpp:100:25: required from ‘bool boost::spirit::qi::parse(const Iterator&, Iterator, const Expr&, Attr&) [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Expr = int; Attr = Parser]’
spirit2.cpp:27:39: required from here
/usr/local/include/boost/spirit/home/qi/parse.hpp:85:9: error: static assertion failed: error_invalid_expression
BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr);
^~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/local/include/boost/spirit/home/qi/detail/parse_auto.hpp:14,
from /usr/local/include/boost/spirit/home/qi/auto.hpp:16,
from /usr/local/include/boost/spirit/home/qi.hpp:15,
from /usr/local/include/boost/spirit/include/qi.hpp:16,
from spirit2.cpp:4:
/usr/local/include/boost/spirit/home/qi/parse.hpp:88:42: error: request for member ‘parse’ in ‘boost::spirit::compile<boost::spirit::qi::domain, int>((* & expr))’, which is of non-class type ‘boost::spirit::result_of::compile<boost::spirit::qi::domain, boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<int>, 0>, boost::spirit::unused_type, void>::type’ {aka ‘int’}
return compile<qi::domain>(expr).parse(first, last, context, unused, attr);
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
In file included from /usr/local/include/boost/spirit/home/qi/auxiliary/attr.hpp:18,
from /usr/local/include/boost/spirit/home/qi/auxiliary.hpp:19,
from /usr/local/include/boost/spirit/home/qi.hpp:16,
from /usr/local/include/boost/spirit/include/qi.hpp:16,
from spirit2.cpp:4:
/usr/local/include/boost/spirit/home/qi/detail/assign_to.hpp: In instantiation of ‘static void boost::spirit::traits::assign_to_attribute_from_value<Attribute, T, Enable>::call(const T_&, Attribute&, mpl_::false_) [with T_ = std::vector<char, std::allocator<char> >; Attribute = long unsigned int; T = std::vector<char, std::allocator<char> >; Enable = void; mpl_::false_ = mpl_::bool_<false>]’:
/usr/local/include/boost/spirit/home/qi/detail/assign_to.hpp:171:17: required from ‘static void boost::spirit::traits::assign_to_attribute_from_value<Attribute, T, Enable>::call(const T&, Attribute&) [with Attribute = long unsigned int; T = std::vector<char, std::allocator<char> >; Enable = void]’
/usr/local/include/boost/spirit/home/qi/detail/assign_to.hpp:370:63: required from ‘void boost::spirit::traits::detail::assign_to(const T&, Attribute&, mpl_::false_) [with T = std::vector<char, std::allocator<char> >; Attribute = long unsigned int; mpl_::false_ = mpl_::bool_<false>]’
/usr/local/include/boost/spirit/home/qi/detail/assign_to.hpp:393:26: required from ‘void boost::spirit::traits::assign_to(const T&, Attribute&) [with T = std::vector<char, std::allocator<char> >; Attribute = long unsigned int]’
/usr/local/include/boost/spirit/home/qi/detail/attributes.hpp:27:30: required from ‘static void boost::spirit::qi::default_transform_attribute<Exposed, Transformed>::post(Exposed&, const Transformed&) [with Exposed = long unsigned int; Transformed = std::vector<char, std::allocator<char> >]’
/usr/local/include/boost/spirit/home/qi/action/action.hpp:71:36: required from ‘bool boost::spirit::qi::action<Subject, Action>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; Context = boost::spirit::context<boost::fusion::cons<long unsigned int&, boost::fusion::nil_>, boost::fusion::vector<> >; Skipper = boost::spirit::unused_type; Attribute = long unsigned int; Subject = boost::spirit::qi::kleene<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::digit, boost::spirit::char_encoding::ascii> > >; Action = boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::phoenix::actor<boost::spirit::attribute<0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<Parser::Parser()::<lambda(auto:1&&)> >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> >]’
/usr/local/include/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:73:54: [ skipping 3 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/local/include/boost/function/function_template.hpp:720:7: required from ‘boost::function4<R, T1, T2, T3, T4>::function4(Functor, typename boost::enable_if_<(! boost::is_integral<Functor>::value), int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::action<boost::spirit::qi::kleene<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::digit, boost::spirit::char_encoding::ascii> > >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::phoenix::actor<boost::spirit::attribute<0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<Parser::Parser()::<lambda(auto:1&&)> >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> > >, mpl_::bool_<true> >; R = bool; T0 = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<long unsigned int&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::unused_type&; typename boost::enable_if_<(! boost::is_integral<Functor>::value), int>::type = int]’
/usr/local/include/boost/function/function_template.hpp:1068:16: required from ‘boost::function<R(T0, T1, T2, T3)>::function(Functor, typename boost::enable_if_<(! boost::is_integral<Functor>::value), int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::action<boost::spirit::qi::kleene<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::digit, boost::spirit::char_encoding::ascii> > >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::phoenix::actor<boost::spirit::attribute<0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<Parser::Parser()::<lambda(auto:1&&)> >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> > >, mpl_::bool_<true> >; R = bool; T0 = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<long unsigned int&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::unused_type&; typename boost::enable_if_<(! boost::is_integral<Functor>::value), int>::type = int]’
/usr/local/include/boost/function/function_template.hpp:1121:5: required from ‘typename boost::enable_if_<(! boost::is_integral<Functor>::value), boost::function<R(T0, T1, T2, T3)>&>::type boost::function<R(T0, T1, T2, T3)>::operator=(Functor) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::action<boost::spirit::qi::kleene<boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::digit, boost::spirit::char_encoding::ascii> > >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::phoenix::actor<boost::spirit::attribute<0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<Parser::Parser()::<lambda(auto:1&&)> >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> > >, mpl_::bool_<true> >; R = bool; T0 = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&; T1 = const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&; T2 = boost::spirit::context<boost::fusion::cons<long unsigned int&, boost::fusion::nil_>, boost::fusion::vector<> >&; T3 = const boost::spirit::unused_type&; typename boost::enable_if_<(! boost::is_integral<Functor>::value), boost::function<R(T0, T1, T2, T3)>&>::type = boost::function<bool(__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&, const __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<long unsigned int&, boost::fusion::nil_>, boost::fusion::vector<> >&, const boost::spirit::unused_type&)>&]’
/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:185:19: required from ‘static void boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::define(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&, const Expr&, mpl_::true_) [with Auto = mpl_::bool_<true>; Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::dereference, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::digit, boost::spirit::char_encoding::ascii> >, 0>&>, 1>&, const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::phoenix::actor<boost::spirit::attribute<0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<Parser::Parser()::<lambda(auto:1&&)> >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> >&>, 2>; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; T1 = long unsigned int(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type; mpl_::true_ = mpl_::bool_<true>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:249:31: required from ‘boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>& boost::spirit::qi::operator%=(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&, Expr&&) [with Expr = const boost::proto::exprns_::expr<boost::proto::tagns_::tag::subscript, boost::proto::argsns_::list2<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::dereference, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::digit, boost::spirit::char_encoding::ascii> >, 0>&>, 1>&, const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::phoenix::actor<boost::spirit::attribute<0> >, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<Parser::Parser()::<lambda(auto:1&&)> >, 0>, boost::phoenix::actor<boost::spirit::argument<0> > >, 2> > >, 2> >&>, 2>; Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; T1 = long unsigned int(); T2 = boost::spirit::unused_type; T3 = boost::spirit::unused_type; T4 = boost::spirit::unused_type]’
spirit2.cpp:16:69: required from here
/usr/local/include/boost/spirit/home/qi/detail/assign_to.hpp:153:20: error: invalid static_cast from type ‘const std::vector<char, std::allocator<char> >’ to type ‘long unsigned int’
attr = static_cast<Attribute>(val);
^~~~~~~~~~~~~~~~~~~~~~~~~~~
The solution is to drop %:
r = (*qi::ascii::digit)[qi::_val = phx::bind(count, qi::_1)];
The important error message is in the last line: error: invalid static_cast from type ‘const std::vector<char, std::allocator<char> >’ to type ‘long unsigned int’
For why it produces vector<char> see here.
There is use of semantic action and:
r %= p and r = p are equivalent if there are no semantic actions
associated with p.
Read more about it here.
The doqtor did an excellent job of introducing the relevant concepts. I'd just like to show some simplification if you have a recent compiler (which it looks like you do):
phx::function count { [](auto&& v) { return v.size(); } };
r = (*digit)[_val = count(_1)];
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace phx = boost::phoenix;
namespace qi = boost::spirit::qi;
using It = std::string::const_iterator;
struct Parser : qi::grammar<It, size_t()> {
Parser() : Parser::base_type(r) {
using namespace qi;
phx::function count { [](auto&& v) { return v.size(); } };
r = (*digit)[_val = count(_1)];
}
private:
qi::rule<It, size_t()> r;
};
int main() {
std::string const s = "123";
int c;
Parser p;
if (qi::parse(s.begin(), s.end(), p, c)) {
std::cout << "Number of digits: " << c << "\n";
}
}
Prints
Number of digits: 3
I tried to compile example file
with gcc 5.3.1 (5.3.1 20160406 (Red Hat 5.3.1-6) (GCC)), boost 1.61.0.
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <iostream>
// Presented are various ways to attach semantic actions
// * Using plain function pointer
// * Using simple function object
namespace client
{
namespace x3 = boost::spirit::x3;
using x3::_attr;
struct print_action
{
template <typename Context>
void operator()(Context const& ctx) const
{
std::cout << _attr(ctx) << std::endl;
}
};
}
int main()
{
using boost::spirit::x3::int_;
using boost::spirit::x3::parse;
using client::print_action;
{ // example using function object
char const *first = "{43}", *last = first + std::strlen(first);
parse(first, last, '{' >> int_[print_action()] >> '}');
}
{ // example using C++14 lambda
char const *first = "{44}", *last = first + std::strlen(first);
auto f = [](auto& ctx){ std::cout << _attr(ctx) << std::endl; };
parse(first, last, '{' >> int_[f] >> '}');
}
return 0;
}
The compile command is:g++ test.cpp -std=c++1y (I just renamed the file.)
I got the following error:
test.cpp: In instantiation of ‘main()::<lambda(auto:1&)> [with auto:1 = const boost::spirit::x3::context<boost::spirit::x3::attr_context_tag, int, boost::spirit::x3::context<boost::spirit::x3::where_context_tag, boost::iterator_range<const char*>, boost::spirit::x3::context<boost::spirit::x3::rule_val_context_tag, const boost::spirit::x3::unused_type, boost::spirit::x3::context<boost::spirit::x3::parse_pass_context_tag, bool, boost::spirit::x3::unused_type> > > >]’:
/usr/local/include/boost/spirit/home/x3/support/utility/is_callable.hpp:20:35: required from ‘struct boost::spirit::x3::is_callable<main()::<lambda(auto:1&)>(const boost::spirit::x3::context<boost::spirit::x3::attr_context_tag, int, boost::spirit::x3::context<boost::spirit::x3::where_context_tag, boost::iterator_range<const char*>, boost::spirit::x3::context<boost::spirit::x3::rule_val_context_tag, const boost::spirit::x3::unused_type, boost::spirit::x3::context<boost::spirit::x3::parse_pass_context_tag, bool, boost::spirit::x3::unused_type> > > >&)>’
/usr/local/include/boost/spirit/home/x3/core/call.hpp:72:28: required from ‘auto boost::spirit::x3::call(F, Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) [with F = main()::<lambda(auto:1&)>; Iterator = const char*; Context = boost::spirit::x3::context<boost::spirit::x3::parse_pass_context_tag, bool, boost::spirit::x3::unused_type>; RuleContext = const boost::spirit::x3::unused_type; Attribute = int]’
/usr/local/include/boost/spirit/home/x3/core/action.hpp:45:17: required from ‘bool boost::spirit::x3::action<Subject, Action>::call_action(Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RuleContext = const boost::spirit::x3::unused_type; Attribute = int; Subject = boost::spirit::x3::int_parser<int>; Action = main()::<lambda(auto:1&)>]’
/usr/local/include/boost/spirit/home/x3/core/action.hpp:57:32: required from ‘bool boost::spirit::x3::action<Subject, Action>::parse_main(Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RuleContext = const boost::spirit::x3::unused_type; Attribute = int; Subject = boost::spirit::x3::int_parser<int>; Action = main()::<lambda(auto:1&)>]’
/usr/local/include/boost/spirit/home/x3/operator/sequence.hpp:32:17: recursively required from ‘bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, boost::spirit::x3::unused_type) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>; Right = boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> >]’
/usr/local/include/boost/spirit/home/x3/operator/sequence.hpp:32:17: required from ‘bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, boost::spirit::x3::unused_type) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> > >; Right = boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>]’
/usr/local/include/boost/spirit/home/x3/core/parse.hpp:35:68: required from ‘bool boost::spirit::x3::parse_main(Iterator&, Iterator, const Parser&, Attribute&) [with Iterator = const char*; Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >; Attribute = const boost::spirit::x3::unused_type]’
/usr/local/include/boost/spirit/home/x3/core/parse.hpp:71:26: required from ‘bool boost::spirit::x3::parse(Iterator&, Iterator, const Parser&) [with Iterator = const char*; Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >]’
test.cpp:47:49: required from here
test.cpp:46:51: 错误:use of ‘template<class Context> decltype(auto) boost::spirit::x3::_attr(const Context&)’ before deduction of ‘auto’
auto f = [](auto& ctx){ std::cout << _attr(ctx) << std::endl; };
^
test.cpp:46:51: 错误:use of ‘decltype(auto) boost::spirit::x3::_attr(const Context&) [with Context = boost::spirit::x3::context<boost::spirit::x3::attr_context_tag, int, boost::spirit::x3::context<boost::spirit::x3::where_context_tag, boost::iterator_range<const char*>, boost::spirit::x3::context<boost::spirit::x3::rule_val_context_tag, const boost::spirit::x3::unused_type, boost::spirit::x3::context<boost::spirit::x3::parse_pass_context_tag, bool, boost::spirit::x3::unused_type> > > >]’ before deduction of ‘auto’
In file included from /usr/local/include/boost/spirit/home/x3/core/action.hpp:13:0,
from /usr/local/include/boost/spirit/home/x3/core.hpp:14,
from /usr/local/include/boost/spirit/home/x3.hpp:20,
from test.cpp:8:
/usr/local/include/boost/spirit/home/x3/core/call.hpp: In instantiation of ‘auto boost::spirit::x3::call(F, Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) [with F = main()::<lambda(auto:1&)>; Iterator = const char*; Context = boost::spirit::x3::context<boost::spirit::x3::parse_pass_context_tag, bool, boost::spirit::x3::unused_type>; RuleContext = const boost::spirit::x3::unused_type; Attribute = int]’:
/usr/local/include/boost/spirit/home/x3/core/action.hpp:45:17: required from ‘bool boost::spirit::x3::action<Subject, Action>::call_action(Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RuleContext = const boost::spirit::x3::unused_type; Attribute = int; Subject = boost::spirit::x3::int_parser<int>; Action = main()::<lambda(auto:1&)>]’
/usr/local/include/boost/spirit/home/x3/core/action.hpp:57:32: required from ‘bool boost::spirit::x3::action<Subject, Action>::parse_main(Iterator&, const Iterator&, const Context&, RuleContext&, Attribute&) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RuleContext = const boost::spirit::x3::unused_type; Attribute = int; Subject = boost::spirit::x3::int_parser<int>; Action = main()::<lambda(auto:1&)>]’
/usr/local/include/boost/spirit/home/x3/operator/sequence.hpp:32:17: recursively required from ‘bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, boost::spirit::x3::unused_type) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>; Right = boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> >]’
/usr/local/include/boost/spirit/home/x3/operator/sequence.hpp:32:17: required from ‘bool boost::spirit::x3::sequence<Left, Right>::parse(Iterator&, const Iterator&, const Context&, RContext&, boost::spirit::x3::unused_type) const [with Iterator = const char*; Context = boost::spirit::x3::unused_type; RContext = const boost::spirit::x3::unused_type; Left = boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> > >; Right = boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>]’
/usr/local/include/boost/spirit/home/x3/core/parse.hpp:35:68: required from ‘bool boost::spirit::x3::parse_main(Iterator&, Iterator, const Parser&, Attribute&) [with Iterator = const char*; Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >; Attribute = const boost::spirit::x3::unused_type]’
/usr/local/include/boost/spirit/home/x3/core/parse.hpp:71:26: required from ‘bool boost::spirit::x3::parse(Iterator&, Iterator, const Parser&) [with Iterator = const char*; Parser = boost::spirit::x3::sequence<boost::spirit::x3::sequence<boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type>, boost::spirit::x3::action<boost::spirit::x3::int_parser<int>, main()::<lambda(auto:1&)> > >, boost::spirit::x3::literal_char<boost::spirit::char_encoding::standard, boost::spirit::x3::unused_type> >]’
test.cpp:47:49: required from here
/usr/local/include/boost/spirit/home/x3/core/call.hpp:72:28: 错误:use of ‘auto boost::spirit::x3::detail::call(F, const Context&, mpl_::true_) [with F = main()::<lambda(auto:1&)>; Context = boost::spirit::x3::context<boost::spirit::x3::attr_context_tag, int, boost::spirit::x3::context<boost::spirit::x3::where_context_tag, boost::iterator_range<const char*>, boost::spirit::x3::context<boost::spirit::x3::rule_val_context_tag, const boost::spirit::x3::unused_type, boost::spirit::x3::context<boost::spirit::x3::parse_pass_context_tag, bool, boost::spirit::x3::unused_type> > > >; mpl_::true_ = mpl_::bool_<true>]’ before deduction of ‘auto’
return detail::call(f, attr_context, is_callable<F(decltype(attr_context) const&)>());
^
I wonder what leads to this error?
P.S: In the file, 错误 means Error.
Note It looks like you linked the wrong sample file. My answer responds to the code shown in the error message instead.
I can't reproduce the problem, but I remember seeing something similar once.
It seems GCC sometimes has trouble doing ADL for a polymorphic lambda parameter type.
The way I got around it was to disable ADL there:
auto f = [](auto& ctx){ std::cout << x3::_attr(ctx) << std::endl; };
or:
auto f = [](auto& ctx){ std::cout << (_attr)(ctx) << std::endl; };
Why does one variant assignment compile while the other does not? The template instances do not share any types and char could be converted to int, say. What is boost::variant trying to do, that it cannot do in the case of the first assignment and that it can do in the case of the second assignment? Error is below.
#include <string>
#include "boost/variant.hpp"
int main()
{
boost::variant<char> v1;
boost::variant<std::string, int, double> v2;
v1 = v2; // compile error
v2 = v1; // compiles fine
return 0;
}
In file included from /usr/include/boost/variant.hpp:17:0,
from v.cpp:3:
/usr/include/boost/variant/variant.hpp: In instantiation of 'int boost::variant<T0, TN>::convert_copy_into::internal_visit(T&, int) const [with T = const std::basic_string<char>; T0_ = char; TN = {}]':
/usr/include/boost/variant/detail/visitation_impl.hpp:113:9: required from 'typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::variant<char>::convert_copy_into; VoidPtrCV = const void*; T = std::basic_string<char>; typename Visitor::result_type = int; mpl_::true_ = mpl_::bool_<true>]'
/usr/include/boost/variant/detail/visitation_impl.hpp:156:9: required from 'typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::variant<char>::convert_copy_into; VoidPtrCV = const void*; T = std::basic_string<char>; NoBackupFlag = boost::variant<std::basic_string<char>, int, double>::has_fallback_type_; typename Visitor::result_type = int]'
/usr/include/boost/variant/detail/visitation_impl.hpp:237:5: required from 'typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>; step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<3l>, std::basic_string<char>, boost::mpl::l_item<mpl_::long_<2l>, int, boost::mpl::l_item<mpl_::long_<1l>, double, boost::mpl::l_end> > > >, boost::mpl::l_iter<boost::mpl::l_end> >; Visitor = boost::variant<char>::convert_copy_into; VoidPtrCV = const void*; NoBackupFlag = boost::variant<std::basic_string<char>, int, double>::has_fallback_type_; typename Visitor::result_type = int; mpl_::false_ = mpl_::bool_<false>]'
/usr/include/boost/variant/variant.hpp:2245:13: required from 'static typename Visitor::result_type boost::variant<T0, TN>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::variant<char>::convert_copy_into; VoidPtrCV = const void*; T0_ = std::basic_string<char>; TN = {int, double}; typename Visitor::result_type = int]'
/usr/include/boost/variant/variant.hpp:2267:13: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/usr/include/boost/variant/variant.hpp:1581:13: required from 'void boost::variant<T0, TN>::convert_construct_variant(Variant&) [with Variant = const boost::variant<std::basic_string<char>, int, double>; T0_ = char; TN = {}]'
/usr/include/boost/variant/variant.hpp:1628:42: required from 'void boost::variant<T0, TN>::convert_construct(const boost::variant<U0, UN ...>&, long int) [with U0 = std::basic_string<char>; UN = {int, double}; T0_ = char; TN = {}]'
/usr/include/boost/variant/variant.hpp:1649:38: required from 'boost::variant<T0, TN>::variant(const T&) [with T = boost::variant<std::basic_string<char>, int, double>; T0_ = char; TN = {}]'
/usr/include/boost/variant/variant.hpp:2059:29: required from 'void boost::variant<T0, TN>::assign(const T&) [with T = boost::variant<std::basic_string<char>, int, double>; T0_ = char; TN = {}]'
/usr/include/boost/variant/variant.hpp:2099:19: required from 'boost::variant<T0, TN>& boost::variant<T0, TN>::operator=(const T&) [with T = boost::variant<std::basic_string<char>, int, double>; T0_ = char; TN = {}]'
v.cpp:10:6: required from here
/usr/include/boost/variant/variant.hpp:1366:61: error: no matching function for call to 'boost::variant<char>::initializer::initialize(void* const&, const std::basic_string<char>&)'
return initializer::initialize(storage_, operand);
^
/usr/include/boost/variant/variant.hpp:1366:61: note: candidates are:
In file included from /usr/include/boost/variant/variant.hpp:32:0,
from /usr/include/boost/variant.hpp:17,
from v.cpp:3:
/usr/include/boost/variant/detail/initializer.hpp:104:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >; Iterator = boost::mpl::l_iter<boost::mpl::list1<char> >; boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param_T = const char&]
static int initialize(void* dest, param_T operand)
^
/usr/include/boost/variant/detail/initializer.hpp:104:24: note: no known conversion for argument 2 from 'const std::basic_string<char>' to 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::list1<char> > >::initializer_node::param_T {aka const char&}'
/usr/include/boost/variant/detail/initializer.hpp:115:24: note: static int boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::initialize(void*, boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param2_T) [with BaseIndexPair = boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >; Iterator = boost::mpl::l_iter<boost::mpl::list1<char> >; boost::detail::variant::make_initializer_node::apply<BaseIndexPair, Iterator>::initializer_node::param2_T = char&&]
static int initialize(void* dest, param2_T operand)
^
/usr/include/boost/variant/detail/initializer.hpp:115:24: note: no known conversion for argument 2 from 'const std::basic_string<char>' to 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::list1<char> > >::initializer_node::param2_T {aka char&&}'
/usr/include/boost/variant/detail/initializer.hpp:149:17: note: static void boost::detail::variant::initializer_root::initialize()
static void initialize();
^
/usr/include/boost/variant/detail/initializer.hpp:149:17: note: candidate expects 0 arguments, 2 provided
A char definitely can be stored in an int but the converse is not always true. Therefore the one that fails to compile would be unsafe at runtime, so you're probably better off with it failing. Cast the int to a char if you must.
This question already has an answer here:
Spirit Qi attribute propagation issue with single-member struct
(1 answer)
Closed 8 years ago.
#include <iostream>
#include <vector>
#include <string>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
namespace qi = boost::spirit::qi;
struct VectorWrapper
{
std::vector<std::string> data;
};
BOOST_FUSION_ADAPT_STRUCT(
VectorWrapper,
(std::vector<std::string>, data)
)
int main ()
{
std::string input("aa aa aa");
std::string::iterator strbegin = input.begin();
qi::rule<std::string::iterator, VectorWrapper(), qi::space_type > testRule =
+(qi::string("aa"));
VectorWrapper result;
bool ok = qi::phrase_parse(
strbegin,
input.end(),
testRule,
qi::space,
result);
if (ok && strbegin == input.end()) {
std::cout << result.data.size();
for (int i = 0; i < result.data.size(); ++i) {
std::cout << result.data[i] << " ";
}
} else {
std::cout << "fail" << std::endl;
std::cout << std::string(strbegin, input.end()) << std::endl;
}
}
I need help to find out problem in this code. Compiler complains about type in VectorWrapper struct but shouldn't BOOST_FUSION_ADAPT_STRUCT add it?
After adding dummy field (from this answer)I am getting the same error:
struct VectorWrapper
{
std::vector<std::string> data;
qi::unused_type dummy;
};
BOOST_FUSION_ADAPT_STRUCT(
VectorWrapper,
(std::vector<std::string>, data)
(qi::unused_type, dummy)
)
The error message:
In file included from /usr/local/include/boost/spirit/home/support/string_traits.hpp:16:0,
from /usr/local/include/boost/spirit/home/support/nonterminal/expand_arg.hpp:20,
from /usr/local/include/boost/spirit/home/support/context.hpp:18,
from /usr/local/include/boost/spirit/home/qi/domain.hpp:18,
from /usr/local/include/boost/spirit/home/qi/meta_compiler.hpp:15,
from /usr/local/include/boost/spirit/home/qi/action/action.hpp:14,
from /usr/local/include/boost/spirit/home/qi/action.hpp:14,
from /usr/local/include/boost/spirit/home/qi.hpp:14,
from /usr/local/include/boost/spirit/include/qi.hpp:16,
from main.cpp:4:
/usr/local/include/boost/spirit/home/support/container.hpp: In instantiation of ‘boost::spirit::traits::container_value<VectorWrapper, void>’:
/usr/local/include/boost/spirit/home/qi/detail/pass_container.hpp:296:66: instantiated from ‘bool boost::spirit::qi::detail::pass_container<F, Attr, Sequence>::dispatch_attribute(const Component&, mpl_::true_) const [with Component = boost::spirit::qi::literal_string<const char (&)[3], false>, F = boost::spirit::qi::detail::fail_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> > >, Attr = VectorWrapper, Sequence = mpl_::bool_<false>, mpl_::true_ = mpl_::bool_<true>]’
/usr/local/include/boost/spirit/home/qi/detail/pass_container.hpp:331:61: instantiated from ‘bool boost::spirit::qi::detail::pass_container<F, Attr, Sequence>::operator()(const Component&) const [with Component = boost::spirit::qi::literal_string<const char (&)[3], false>, F = boost::spirit::qi::detail::fail_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> > >, Attr = VectorWrapper, Sequence = mpl_::bool_<false>]’
/usr/local/include/boost/spirit/home/qi/operator/plus.hpp:63:13: instantiated from ‘bool boost::spirit::qi::plus<Subject>::parse_container(F) const [with F = boost::spirit::qi::detail::pass_container<boost::spirit::qi::detail::fail_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> > >, VectorWrapper, mpl_::bool_<false> >, Subject = boost::spirit::qi::literal_string<const char (&)[3], false>]’
/usr/local/include/boost/spirit/home/qi/operator/plus.hpp:85:13: instantiated from ‘bool boost::spirit::qi::plus<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Context = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, Attribute = VectorWrapper, Subject = boost::spirit::qi::literal_string<const char (&)[3], false>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:43:54: instantiated from ‘bool boost::spirit::qi::detail::parser_binder<Parser, Auto>::call(Iterator&, const Iterator&, Context&, const Skipper&, mpl_::false_) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, Context = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, Parser = boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, Auto = mpl_::bool_<false>, mpl_::false_ = mpl_::bool_<false>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:53:67: [ skipping 3 instantiation contexts ]
/usr/local/include/boost/function/function_template.hpp:722:7: instantiated from ‘boost::function4<R, T1, T2, T3, T4>::function4(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, mpl_::bool_<false> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/local/include/boost/function/function_template.hpp:1069:16: instantiated from ‘boost::function<R(T0, T1, T2, T3)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, mpl_::bool_<false> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/local/include/boost/function/function_template.hpp:1124:5: instantiated from ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type boost::function<R(T0, T1, T2, T3)>::operator=(Functor) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, mpl_::bool_<false> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type = boost::function<bool(__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&)>&]’
/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:182:13: instantiated from ‘static void boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::define(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&, const Expr&, mpl_::true_) [with Auto = mpl_::bool_<false>, Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::unary_plus, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::char_code<boost::spirit::tag::string, boost::spirit::char_encoding::standard>, boost::fusion::vector1<const char (&)[3]> > >, 0l>&>, 1l>, Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, T1 = VectorWrapper(), T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>, T3 = boost::spirit::unused_type, T4 = boost::spirit::unused_type, boost::spirit::qi::rule<Iterator, T1, T2, T3, T4> = boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, VectorWrapper(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l> >, mpl_::true_ = mpl_::bool_<true>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:191:13: instantiated from ‘boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::rule(const Expr&, const string&) [with Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::unary_plus, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::char_code<boost::spirit::tag::string, boost::spirit::char_encoding::standard>, boost::fusion::vector1<const char (&)[3]> > >, 0l>&>, 1l>, Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, T1 = VectorWrapper(), T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>, T3 = boost::spirit::unused_type, T4 = boost::spirit::unused_type, std::string = std::basic_string<char>]’
main.cpp:27:27: instantiated from here
/usr/local/include/boost/spirit/home/support/container.hpp:116:12: error: no type named ‘value_type’ in ‘struct VectorWrapper’
In file included from /usr/local/include/boost/spirit/home/qi/operator/kleene.hpp:20:0,
from /usr/local/include/boost/spirit/home/qi/directive/repeat.hpp:18,
from /usr/local/include/boost/spirit/home/qi/directive.hpp:23,
from /usr/local/include/boost/spirit/home/qi.hpp:19,
from /usr/local/include/boost/spirit/include/qi.hpp:16,
from main.cpp:4:
/usr/local/include/boost/spirit/home/qi/detail/pass_container.hpp: In member function ‘bool boost::spirit::qi::detail::pass_container<F, Attr, Sequence>::dispatch_attribute(const Component&, mpl_::true_) const [with Component = boost::spirit::qi::literal_string<const char (&)[3], false>, F = boost::spirit::qi::detail::fail_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> > >, Attr = VectorWrapper, Sequence = mpl_::bool_<false>, mpl_::true_ = mpl_::bool_<true>]’:
/usr/local/include/boost/spirit/home/qi/detail/pass_container.hpp:331:61: instantiated from ‘bool boost::spirit::qi::detail::pass_container<F, Attr, Sequence>::operator()(const Component&) const [with Component = boost::spirit::qi::literal_string<const char (&)[3], false>, F = boost::spirit::qi::detail::fail_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> > >, Attr = VectorWrapper, Sequence = mpl_::bool_<false>]’
/usr/local/include/boost/spirit/home/qi/operator/plus.hpp:63:13: instantiated from ‘bool boost::spirit::qi::plus<Subject>::parse_container(F) const [with F = boost::spirit::qi::detail::pass_container<boost::spirit::qi::detail::fail_function<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> > >, VectorWrapper, mpl_::bool_<false> >, Subject = boost::spirit::qi::literal_string<const char (&)[3], false>]’
/usr/local/include/boost/spirit/home/qi/operator/plus.hpp:85:13: instantiated from ‘bool boost::spirit::qi::plus<Subject>::parse(Iterator&, const Iterator&, Context&, const Skipper&, Attribute&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Context = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, Attribute = VectorWrapper, Subject = boost::spirit::qi::literal_string<const char (&)[3], false>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:43:54: instantiated from ‘bool boost::spirit::qi::detail::parser_binder<Parser, Auto>::call(Iterator&, const Iterator&, Context&, const Skipper&, mpl_::false_) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, Context = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, Parser = boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, Auto = mpl_::bool_<false>, mpl_::false_ = mpl_::bool_<false>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp:53:67: instantiated from ‘bool boost::spirit::qi::detail::parser_binder<Parser, Auto>::operator()(Iterator&, const Iterator&, Context&, const Skipper&) const [with Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, Skipper = boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, Context = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >, Parser = boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, Auto = mpl_::bool_<false>]’
/usr/local/include/boost/function/function_template.hpp:132:42: [ skipping 2 instantiation contexts ]
/usr/local/include/boost/function/function_template.hpp:722:7: instantiated from ‘boost::function4<R, T1, T2, T3, T4>::function4(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, mpl_::bool_<false> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/local/include/boost/function/function_template.hpp:1069:16: instantiated from ‘boost::function<R(T0, T1, T2, T3)>::function(Functor, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, mpl_::bool_<false> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, int>::type = int]’
/usr/local/include/boost/function/function_template.hpp:1124:5: instantiated from ‘typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type boost::function<R(T0, T1, T2, T3)>::operator=(Functor) [with Functor = boost::spirit::qi::detail::parser_binder<boost::spirit::qi::plus<boost::spirit::qi::literal_string<const char (&)[3], false> >, mpl_::bool_<false> >, R = bool, T0 = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T1 = const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, T2 = boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, T3 = const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&, typename boost::enable_if_c<boost::type_traits::ice_not<boost::is_integral<Functor>::value>::value, boost::function<R(T0, T1, T2, T3)>&>::type = boost::function<bool(__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, const __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >&, boost::spirit::context<boost::fusion::cons<VectorWrapper&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >&)>&]’
/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:182:13: instantiated from ‘static void boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::define(boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>&, const Expr&, mpl_::true_) [with Auto = mpl_::bool_<false>, Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::unary_plus, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::char_code<boost::spirit::tag::string, boost::spirit::char_encoding::standard>, boost::fusion::vector1<const char (&)[3]> > >, 0l>&>, 1l>, Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, T1 = VectorWrapper(), T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>, T3 = boost::spirit::unused_type, T4 = boost::spirit::unused_type, boost::spirit::qi::rule<Iterator, T1, T2, T3, T4> = boost::spirit::qi::rule<__gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, VectorWrapper(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l> >, mpl_::true_ = mpl_::bool_<true>]’
/usr/local/include/boost/spirit/home/qi/nonterminal/rule.hpp:191:13: instantiated from ‘boost::spirit::qi::rule<Iterator, T1, T2, T3, T4>::rule(const Expr&, const string&) [with Expr = boost::proto::exprns_::expr<boost::proto::tagns_::tag::unary_plus, boost::proto::argsns_::list1<const boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::terminal_ex<boost::spirit::tag::char_code<boost::spirit::tag::string, boost::spirit::char_encoding::standard>, boost::fusion::vector1<const char (&)[3]> > >, 0l>&>, 1l>, Iterator = __gnu_cxx::__normal_iterator<char*, std::basic_string<char> >, T1 = VectorWrapper(), T2 = boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::standard> >, 0l>, T3 = boost::spirit::unused_type, T4 = boost::spirit::unused_type, std::string = std::basic_string<char>]’
main.cpp:27:27: instantiated from here
/usr/local/include/boost/spirit/home/qi/detail/pass_container.hpp:296:66: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_value<VectorWrapper, void>’
/usr/local/include/boost/spirit/home/qi/detail/pass_container.hpp:309:15: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_value<VectorWrapper, void>’
make: *** [all] Error 1
You need to emit an unused type in your rule:
qi::rule<std::string::iterator, VectorWrapper(), qi::space_type > testRule =
+(qi::string("aa")) >> qi::attr(false);
The linked answer should be enough. Since you report trouble still: here's something that works on my compilers:
qi::rule<std::string::iterator, VectorWrapper(), qi::space_type > testRule =
qi::eps >> +(qi::string("aa"));
See it Live On Coliru
I wanted to write a higher order function filter with C++. The code I have come up with so far is as follows:
#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
#include <vector>
#include <list>
#include <iterator>
using namespace std;
bool isOdd(int const i) {
return i % 2 != 0;
}
template <
template <class, class> class Container,
class Predicate,
class Allocator,
class A
>
Container<A, Allocator> filter(Container<A, Allocator> const & container, Predicate const & pred) {
Container<A, Allocator> filtered(container);
container.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end());
return filtered;
}
int main() {
int const a[] = {23, 12, 78, 21, 97, 64};
vector<int const> const v(a, a + 6);
vector<int const> const filtered = filter(v, isOdd);
copy(filtered.begin(), filtered.end(), ostream_iterator<int const>(cout, " "));
}
However on compiling this code, I get the following error messages that I am unable to understand and hence get rid of:
/usr/include/c++/4.3/ext/new_allocator.h: In instantiation of ‘__gnu_cxx::new_allocator<const int>’:
/usr/include/c++/4.3/bits/allocator.h:84: instantiated from ‘std::allocator<const int>’
/usr/include/c++/4.3/bits/stl_vector.h:75: instantiated from ‘std::_Vector_base<const int, std::allocator<const int> >’
/usr/include/c++/4.3/bits/stl_vector.h:176: instantiated from ‘std::vector<const int, std::allocator<const int> >’
Filter.cpp:29: instantiated from here
/usr/include/c++/4.3/ext/new_allocator.h:82: error: ‘const _Tp* __gnu_cxx::new_allocator<_Tp>::address(const _Tp&) const [with _Tp = const int]’ cannot be overloaded
/usr/include/c++/4.3/ext/new_allocator.h:79: error: with ‘_Tp* __gnu_cxx::new_allocator<_Tp>::address(_Tp&) const [with _Tp = const int]’
Filter.cpp: In function ‘Container<A, Allocator> filter(const Container<A, Allocator>&, const Predicate&) [with Container = std::vector, Predicate = bool ()(int), Allocator = std::allocator<const int>, A = const int]’:
Filter.cpp:30: instantiated from here
Filter.cpp:23: error: passing ‘const std::vector<const int, std::allocator<const int> >’ as ‘this’ argument of ‘__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::erase(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, __gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >) [with _Tp = const int, _Alloc = std::allocator<const int>]’ discards qualifiers
/usr/include/c++/4.3/bits/stl_algo.h: In function ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >, _Predicate = bool (*)(int)]’:
Filter.cpp:23: instantiated from ‘Container<A, Allocator> filter(const Container<A, Allocator>&, const Predicate&) [with Container = std::vector, Predicate = bool ()(int), Allocator = std::allocator<const int>, A = const int]’
Filter.cpp:30: instantiated from here
/usr/include/c++/4.3/bits/stl_algo.h:821: error: assignment of read-only location ‘__result.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = const int*, _Container = std::vector<const int, std::allocator<const int> >]()’
/usr/include/c++/4.3/ext/new_allocator.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::deallocate(_Tp*, size_t) [with _Tp = const int]’:
/usr/include/c++/4.3/bits/stl_vector.h:150: instantiated from ‘void std::_Vector_base<_Tp, _Alloc>::_M_deallocate(_Tp*, size_t) [with _Tp = const int, _Alloc = std::allocator<const int>]’
/usr/include/c++/4.3/bits/stl_vector.h:136: instantiated from ‘std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp = const int, _Alloc = std::allocator<const int>]’
/usr/include/c++/4.3/bits/stl_vector.h:286: instantiated from ‘std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const _Alloc&) [with _InputIterator = const int*, _Tp = const int, _Alloc = std::allocator<const int>]’
Filter.cpp:29: instantiated from here
/usr/include/c++/4.3/ext/new_allocator.h:98: error: invalid conversion from ‘const void*’ to ‘void*’
/usr/include/c++/4.3/ext/new_allocator.h:98: error: initializing argument 1 of ‘void operator delete(void*)’
/usr/include/c++/4.3/bits/stl_algobase.h: In function ‘_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false, _II = const int*, _OI = const int*]’:
/usr/include/c++/4.3/bits/stl_algobase.h:435: instantiated from ‘_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false, _II = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >, _OI = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >]’
/usr/include/c++/4.3/bits/stl_algobase.h:466: instantiated from ‘_OI std::copy(_II, _II, _OI) [with _II = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >, _OI = __gnu_cxx::__normal_iterator<const int*, std::vector<const int, std::allocator<const int> > >]’
/usr/include/c++/4.3/bits/vector.tcc:136: instantiated from ‘__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> > std::vector<_Tp, _Alloc>::erase(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, __gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >) [with _Tp = const int, _Alloc = std::allocator<const int>]’
Filter.cpp:23: instantiated from ‘Container<A, Allocator> filter(const Container<A, Allocator>&, const Predicate&) [with Container = std::vector, Predicate = bool ()(int), Allocator = std::allocator<const int>, A = const int]’
Filter.cpp:30: instantiated from here
/usr/include/c++/4.3/bits/stl_algobase.h:396: error: no matching function for call to ‘std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m(const int*&, const int*&, const int*&)’
Please tell me what I am doing wrong here and what is the correct way to achieve the kind of higher order polymorphism I want.
Thanks.
EDIT:
Thank you, everyone. Here's the new code I got after applying your suggestions (and it works now, yay!)
#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
#include <vector>
#include <list>
#include <iterator>
using namespace std;
bool isOdd(int const i) {
return i % 2 != 0;
}
template <
template <typename, typename> class Container,
typename Predicate,
typename Allocator,
typename A
>
Container<A, Allocator> filter(Container<A, Allocator> const & container, Predicate const & pred) {
Container<A, Allocator> filtered(container);
filtered.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end());
return filtered;
}
int main() {
int a[] = {23, 12, 78, 21, 97, 64};
vector<int> v(a, a + 6);
vector<int> filtered = filter(v, isOdd);
copy(filtered.begin(), filtered.end(), ostream_iterator<int>(cout, " "));
}
Why is your Container parametrized at all?
template <typename C, typename P>
C filter(C const & container, P pred) {
C filtered(container);
filtered.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end());
return filtered;
}
Works just as well. Notice that I passed P by value rather than by const reference, as advised by Meyers in Effective C++ (iterators and functors should be passed by value).
what about remove_copy_if instead ? (with isEven()). It's already built for you.
The error is not in filter, but in:
int main() {
int const a[] = {23, 12, 78, 21, 97, 64};
vector<int const> const v(a, a + 6);
}
You can't have a vector of const stuff. Remove the inner const:
int main() {
int const a[] = {23, 12, 78, 21, 97, 64};
vector<int> const v(a, a + 6);
}
(And of course, filtered.erase, not container.erase.)
container is a const-reference. You can't call erase() on it. You probably mean to call
filtered.erase(remove_if(filtered.begin(), filtered.end(), pred), filtered.end());