Boost has a library named Spirit that makes heavy use of TMP in order to facilitate the easy creation of parsers in a BNF like syntax. By default it is intended to work with standard library strings. I'm using it in a Qt based project, where QString
is the primary string type. How can I use boost::spirit
with QString
s?
There are two parts to making boost::spirit
and QString
cooperate; getting data in and getting data out. We'll start with the latter. As far as boost::spirit
is concerned, QString
is an unknown type. We must give it a few container traits so that it knows how to interact:
#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
#include <QString>
namespace boost { namespace spirit { namespace x3 { namespace traits {
template<>
struct push_back_container<QString>
{
template<typename T>
static bool call(QString& c, T&& val)
{
c.push_back(std::move(val));
return true;
}
};
template<>
struct append_container<QString>
{
template<typename Iterator>
static bool call(QString& c, Iterator first, Iterator last)
{
c.append(first, std::distance(first, last));
return true;
}
};
template<>
struct is_empty_container<QString>
{
static bool call(QString const& c)
{
return c.isEmpty();
}
};
}}}}
Depending on your particular use case, you may also want to parse from QString
s. There is probably a way to teach boost::spirit
about QChar
(the iterable type of QString
), but I don't have the patience for that. The alternative is to create an iterator_adaptor
whose value type is char16_t
. Although uint32_t
is the type boost::spirit
uses to represent unicode values, it can't be unambiguously converted to QChar
whereas char16_t
can. QString
operates on a UTF16 basis, so this type is sufficiently wide enough. Note you'll need to turn unicode support on (#define BOOST_SPIRIT_X3_UNICODE
).
#include <boost/iterator/iterator_adaptor.hpp>
#include <QString>
template<typename QStringIterator>
class QStringSpiritUnicodeIteratorAdaptor : public boost::iterator_adaptor<
QStringSpiritUnicodeIteratorAdaptor<QStringIterator>,
QStringIterator, char16_t, boost::forward_traversal_tag, char16_t>
{
public:
using boost::iterator_adaptor<
QStringSpiritUnicodeIteratorAdaptor<QStringIterator>,
QStringIterator, char16_t, boost::forward_traversal_tag,
char16_t>::iterator_adaptor;
private:
friend class boost::iterator_core_access;
char16_t dereference() const
{
return static_cast<char16_t>(this->base_reference()->unicode());
}
};
using QStringSpiritUnicodeIterator =
QStringSpiritUnicodeIteratorAdaptor<QString::iterator>;
using QStringSpiritUnicodeConstIterator =
QStringSpiritUnicodeIteratorAdaptor<QString::const_iterator>;
This is used as follows:
QString text = "blah blah blah";
QStringSpiritUnicodeIterator begin(text.begin());
QStringSpiritUnicodeIterator end(text.end());
...::x3::phrase_parse(begin, end, ...);