如何将 boost::spirit X3 与 QString 结合使用?

How can I use boost::spirit X3 in conjunction with QString?

Boost 有一个名为 Spirit 的库,它大量使用 TMP 以便于在类似 BNF 的语法中轻松创建解析器。默认情况下,它旨在与标准库字符串一起使用。我在基于 Qt 的项目中使用它,其中 QString 是主要字符串类型。如何将 boost::spiritQString 一起使用?

boost::spiritQString合作有两个部分;获取数据和获取数据。我们将从后者开始。就boost::spirit而言,QString是未知类型。我们必须给它一些容器特征,以便它知道如何交互:

#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();
    }
};

}}}}

根据您的特定用例,您可能还想从 QString 解析 。可能有一种方法可以教 boost::spirit 关于 QCharQString 的可迭代类型),但我没有耐心。另一种方法是创建一个 iterator_adaptor,其值类型为 char16_t。尽管 uint32_tboost::spirit 用来表示 unicode 值的类型,它不能明确地转换为 QCharchar16_t 可以。 QString是在UTF16基础上运行的,所以这个类型足够宽了。请注意,您需要打开 unicode 支持 (#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>;

这个用法如下:

QString text = "blah blah blah";
QStringSpiritUnicodeIterator begin(text.begin());    
QStringSpiritUnicodeIterator end(text.end());

...::x3::phrase_parse(begin, end, ...);