2

In my my previous question it was suggested that the performance of my boost::spirit::x3 parser could be improved by parsing into a boost::string_view using the raw directive.

However, I have difficulties getting it to compile. This is what I found out:

  • Before x3, one had to specialize assign_to_attribute_from_iterators (see e.g. this SO answer) to handle the raw directive.

  • x3 now uses the move_to free function instead (see e.g. this SO answer).

I therefore added a move_to overload which works if I parse from char*:

#include <iostream>
#include <string>

#include <boost/utility/string_view.hpp>

namespace boost {
namespace spirit { namespace x3 { namespace traits {

template <typename It>
void move_to(It b, It e, boost::string_view& v)
{
    v = boost::string_view(b, std::size_t(std::distance(b,e)));
}

} } }

} // namespace boost

#include <boost/spirit/home/x3.hpp>

namespace parser
{
    namespace x3 = boost::spirit::x3;
    using x3::char_;
    using x3::raw;

    const auto str  = raw[ +~char_('_')] >> '_';
}

int main()
{
    std::string input = "hello world_";

    boost::string_view str; 
    parse(input.data(), input.data()+input.size(), parser::str, str);

    std::cout << str;
}

live example

However, it does not compile:

1) If I parse using std::string::const_iterator

parse(input.cbegin(), input.cend(), parser::str, str);

The constructor of boost::string_view either expects a const char* or a std::string&.

main.cpp:12:16: error: no matching function for call to 'boost::basic_string_view<char, std::char_traits<char> >::basic_string_view(__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >&, std::size_t)'
     v = boost::string_view(b, std::size_t(std::distance(b,e)));
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

live example

How can I instantiate a boost::string_view from std::string::const_iterator?

2) If boost/spirit/home/x3.hpp is included prior to the move_to overload

live example

Why is my overload not chosen? Isn't it a better overload than any of those defined in boost/spirit/home/x3/support/traits/move_to.hpp? How can I make sure my overload is chosen regardless the order of inclusion?

Community
  • 1
  • 1
m.s.
  • 16,063
  • 7
  • 53
  • 88
  • 2) is partial ordering. I don't think there is a way around it (I haven't found one before) - see http://en.cppreference.com/w/cpp/language/partial_specialization#Partial_ordering – sehe Aug 30 '16 at 11:20
  • @sehe I think it would help if `directive/raw.hpp` was changed to this: [see here @ line 42-44](http://coliru.stacked-crooked.com/a/7eeab94a4474ff18), then ADL could be used and the overload would reside in `namespace boost` – m.s. Aug 30 '16 at 11:24

1 Answers1

2

I'd simply write what you want:

v = boost::string_view(&*b, std::distance(b,e));

You might want to check that storage is contiguous¹ as a concept check for your input range. In that respect, it might be clearer to also require the iterator to be random-access, and write:

v = boost::string_view(&*b, e-b);

¹ this is a requirement for string_view anyways

sehe
  • 374,641
  • 47
  • 450
  • 633