I'm very new with boost spirit (and with boost). Its very interesting library.
I use qtcreator + MinGW 5.3.
I simply add every source file from git_hub_calc8 into new project and add some boost library, but i got the following error trying to build (All other examples work fine)
C:\Program Files\boost\boost\boost\spirit\home\x3\nonterminal\rule.hpp:113: ошибка: undefined reference to `bool client::parser::parse_rule<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> >, std::__cxx11::list<client::ast::statement, std::allocator<client::ast::statement> > >(boost::spirit::x3::rule<client::parser::statement_class, std::__cxx11::list<client::ast::statement, std::allocator<client::ast::statement> >, false>, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const, boost::spirit::x3::unused_type> > const&, std::__cxx11::list<client::ast::statement, std::allocator<client::ast::statement> >&)'
What did i wrong? How should i create project with this example?
Seems like a problem with BOOST_SPIRIT_DECLARE beacause a place pointed out by error is call for a template function connected with this define
(template <typename Iterator, typename Context, typename Attribute_>
bool parse(Iterator& first, Iterator const& last
, Context const& context, unused_type, Attribute_& attr) const
{
return parse_rule(*this, first, last, context, attr);
}
The BOOST_SPIRIT_INSTANTIATE
marco is equivalent to doing
namespace client { namespace parser
{
template bool parse_rule<iterator_type, context_type, statement_type::attribute_type>(
statement_type rule_, iterator_type &first, iterator_type const &last,
context_type const &context,
statement_type ::attribute_type &attr);
;
}}
So the crucial bit is that iterator_type
and context_type
match exactly the ones required at the call site. Now, the unresolved symbol is (demangled):
bool client::parser::parse_rule<
__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >,
boost::spirit::x3::context<
boost::spirit::x3::error_handler_tag,
std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<
char const *, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >,
boost::spirit::x3::context<
boost::spirit::x3::skipper_tag,
boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const,
boost::spirit::x3::unused_type> >,
std::__cxx11::list<client::ast::statement, std::allocator<client::ast::statement> >
>
(boost::spirit::x3::rule<client::parser::statement_class, std::__cxx11::list<client::ast::statement, std::allocator<client::ast::statement> >, false>,
__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&,
__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&,
boost::spirit::x3::context<
boost::spirit::x3::error_handler_tag,
std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<
char const *, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >,
boost::spirit::x3::context<
boost::spirit::x3::skipper_tag,
boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const,
boost::spirit::x3::unused_type> > const &,
std::__cxx11::list<client::ast::statement, std::allocator<client::ast::statement> >&)
This implies the iterator_type should be:
__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >,
Which is indeed what std::string::const_iterator
expands to on my system. So, the mismatch is likely in the context type. By adding a forced type error above the BOOST_SPIRIT_INSTANTIATE
invocation like so:
struct {} _ = *static_cast<client::parser::context_type*>(nullptr);
I was able to force the compiler to output the expanded type of context_type
at the point of instantiation:
statement.cpp:12 error: conversion from ‘client::parser::context_type {aka boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, const std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type> >}’ to non-scalar type ‘client::parser::<anonymous struct>’ requested
Which tells us the context type is (formatted for legibility):
boost::spirit::x3::context<
boost::spirit::x3::error_handler_tag,
const std::reference_wrapper<boost::spirit::x3::error_handler<
__gnu_cxx::__normal_iterator<const char *, std::__cxx11::basic_string<char> > > >,
boost::spirit::x3::context<
boost::spirit::x3::skipper_tag,
boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const,
boost::spirit::x3::unused_type> >,
BUT: the linker has it as
boost::spirit::x3::context<
boost::spirit::x3::error_handler_tag,
std::reference_wrapper<boost::spirit::x3::error_handler<
__gnu_cxx::__normal_iterator<const char *, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >,
boost::spirit::x3::context<
boost::spirit::x3::skipper_tag,
boost::spirit::x3::char_class<boost::spirit::char_encoding::ascii, boost::spirit::x3::space_tag> const,
boost::spirit::x3::unused_type> >
The most conspicuous difference is in the spelling of the defaulted template arguments on std::basic_string
(char_traits
and the allocator
), but that's not actually a difference. The difference that DOES matter, though, is the absense of const
with the reference_wrapper<>
type.
Fixing It
I suppose this might have been a change once upon a time in the history of X3. The easiest fix in this case is to drop the const
in config.hpp:
typedef x3::context<
error_handler_tag
, std::reference_wrapper<error_handler_type>
, phrase_context_type>
context_type;
And indeed, it now compiles