Использование выражения auto_ в boost :: spirit с std :: vectors

Я новичок в boost :: spirit. Я хотел бы разобрать строку объектов, разделенных запятыми, в std :: vector (аналогично тому, как в руководствах). Строка может быть разных типов (известных во время компиляции): целые числа, например "1,2,3", строки "Apple, Orange, Banana" и т.д. и т.д. Я хотел бы иметь единый интерфейс для всех типов.

Если я разбираю один элемент, я могу использовать выражение auto_. Возможен ли аналогичный интерфейс с векторами? Могу ли я определить правило, которое, учитывая параметр шаблона, действительно может анализировать этот вектор?

Вот простой пример кода (который не компилируется из-за последнего вызова фразе_parse):

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

#include <iostream>
#include <vector>
#include <boost/spirit/include/qi_auto.hpp>


namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;

using qi::auto_;
using qi::phrase_parse;
using ascii::space;
using phoenix::push_back;


int main()
{
    std::string line1 = "3";
    std::string line2 = "1, 2, 3";

    int v;
    std::vector<int> vector;

    typedef std::string::iterator stringIterator;

    stringIterator first = line1.begin();
    stringIterator last  = line1.end();

    namespace qi    = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;

    bool r1 = qi::phrase_parse( first,
                                last,
                                qi::auto_,
                                ascii::space,
                                v );

    first = line2.begin();
    last  = line2.end();

    //The following call is wrong!
    bool r2 = qi::phrase_parse( first,
                                last,
                              //  Begin grammar
                               (
                                qi::auto_[push_back(phoenix::ref(vector), qi::_1)]
                                >> *(',' >> qi::auto_[push_back(phoenix::ref(vector),qi::_1)])
                               ),
                              //  End grammar
                                ascii::space, 
                                vector);
    return 0;
}

ОБНОВЛЕНИЕ

Я нашел решение, в случае, если размер вектора известен до разбора. С другой стороны, я не могу использовать синтаксис *( ',' >> qi::auto_ ).

#include <boost/spirit/include/qi.hpp>

namespace qi     = boost::spirit::qi;

int main()
{
    std::string s = "1, 2, 3";

    std::vector<int> vector;
    //This works
    qi::phrase_parse(s.begin(), s.end(), qi::auto_ >> ',' >> qi::auto_  >> ',' >> qi::auto_  , qi::blank, vector);
    //This does not compile
    qi::phrase_parse(s.begin(), s.end(), qi::auto_ >> *( ',' >> qi::auto_ ) , qi::blank, vector);

    for(int i = 0; i < vector.size() ; i++)
        std::cout << i << ": " << vector[i] << std::endl;

    return 0;
}

Более того, используя auto_, я не могу разобрать строку. Можно ли определить функцию электронного шаблона, в которой грамматика может быть выведена с помощью параметра шаблона?

template< typename T >
void MyParse(std::string& line, std::vector<T> vec)
{
     qi::phrase_parse( line.begin(), 
                       line.end(), 
                       /* 
                       How do I define a grammar based on T
                       such as: 
                          double_ >> *( ',' >> double_ )    for T = double
                       +qi::alnum >> *( ',' >> +qi::alnum ) for T = std::string
                       */, 
                       qi::blank, 
                       vec);
}

person srossi    schedule 25.01.2015    source источник
comment
Игнорируя проблему с std :: string, вы хотите использовать анализатор списка (auto_%',').   -  person llonesmiz    schedule 25.01.2015
comment
Взглянув на пример, здесь, это, похоже, работает (вы можете изменить +(char_-',') на +alnum, если хотите).   -  person llonesmiz    schedule 25.01.2015
comment
@cv_and_he Работает как шарм! Духовная документация анализатор списка утверждает, что для` a% b `: это эквивалентно ›› * (b ›› a). Но с auto_ все иначе, потому что он даже не компилируется.   -  person srossi    schedule 25.01.2015
comment
auto_ не подходит для std :: string, потому что он действительно может соответствовать чему угодно   -  person sehe    schedule 25.01.2015
comment
@cv_and_he Я придумал менее навязчивый способ справиться с std::string vs. auto_, как я думаю в моем обновленном ответе. Вам, вероятно, следует опубликовать эту версию, основанную на create_parser<>, в качестве ответа ... Она того стоит.   -  person sehe    schedule 25.01.2015


Ответы (1)


auto_ имеет встроенную поддержку атрибутов контейнера:

Live On Coliru

std::istringstream iss("1 2 3 4 5; 6 7 8 9;");
iss.unsetf(std::ios::skipws);

std::vector<int> i;
std::vector<double> d;

if (iss >> qi::phrase_match(qi::auto_ >> ";" >> qi::auto_, qi::space, i, d))
{
    for (auto e:i) std::cout << "int: " << e << "\n";
    for (auto e:d) std::cout << "double: " << e << "\n";
}

Отпечатки

int: 1
int: 2
int: 3
int: 4
int: 5
double: 6
double: 7
double: 8
double: 9

Таким образом, вы могли бы написать свою функцию-шаблон, используя ',' в качестве шкипера. Я бы предпочел вариант operator%.

Простой взгляд

template<typename Container>
void MyParse(std::string const& line, Container& container)
{
    auto f(line.begin()), l(line.end());
    bool ok = qi::phrase_parse(
            f, l,
            qi::auto_ % ',', qi::blank, container);

    if (!ok || (f!=l))
        throw "parser error: '" + std::string(f,l) + "'"; // FIXME
} 

Вариант 2

template<typename Container>
void MyParse(std::string const& line, Container& container)
{
    auto f(line.begin()), l(line.end());
    bool ok = qi::phrase_parse(
            f, l,
            qi::auto_, qi::blank | ',', container);

    if (!ok || (f!=l))
        throw "parser error: '" + std::string(f,l) + "'"; // FIXME
} 

Решение дела string (и других):

Если тип элемента не выводится Духом (что угодно может быть проанализировано в строку), просто возьмите дополнительный синтаксический анализатор / грамматику, который знает, как анализировать тип элемента?

template<typename Container, typename ElementParser = qi::auto_type>
void MyParse(std::string const& line, Container& container, ElementParser const& elementParser = ElementParser())
{
    auto f(line.begin()), l(line.end());
    bool ok = qi::phrase_parse(
            f, l,
            elementParser % ",", qi::blank, container);

    if (!ok || (f!=l))
        throw "parser error: '" + std::string(f,l) + "'"; // FIXME
} 

Теперь он отлично разбирает строки:

std::vector<int> i;
std::set<std::string> s;

MyParse("1,22,33,44,15", i);
MyParse("1,22,33,44,15", s, *~qi::char_(","));

for(auto e:i) std::cout << "i: " << e << "\n";
for(auto e:s) std::cout << "s: " << e << "\n";

Отпечатки

i: 1
i: 22
i: 33
i: 44
i: 15
s: 1
s: 15
s: 22
s: 33
s: 44

Полный список

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <iostream>

namespace qi = boost::spirit::qi;

    template<typename Container, typename ElementParser = qi::auto_type>
    void MyParse(std::string const& line, Container& container, ElementParser const& elementParser = ElementParser())
    {
        auto f(line.begin()), l(line.end());
        bool ok = qi::phrase_parse(
                f, l,
                elementParser % ",", qi::blank, container);

        if (!ok || (f!=l))
            throw "parser error: '" + std::string(f,l) + "'"; // FIXME
    } 

#include <set>

int main()
{
    std::vector<int> i;
    std::set<std::string> s;

    MyParse("1,22,33,44,15", i);
    MyParse("1,22,33,44,15", s, *~qi::char_(","));

    for(auto e:i) std::cout << "i: " << e << "\n";
    for(auto e:s) std::cout << "s: " << e << "\n";
}
person sehe    schedule 25.01.2015
comment
Обновлено для работы с типами элементов, не поддерживающими auto_ - person sehe; 25.01.2015
comment
Очень хороший подход, я хотел бы дать вам еще +1. Не стесняйтесь добавлять подход create_parser, если считаете, что он достоин (я не думаю). - person llonesmiz; 25.01.2015
comment
@cv_and_he Я думаю, что очень хорошо об этом упомянуть (все эти auto_ дела в конце концов не волшебство). Тем не менее, я думаю, что есть проблемы со специализацией этого для специфичного для парсера поведения. Внешняя связь может вызвать нарушения ODR. Я не разбираюсь в юридических стандартах, но обычно стараюсь держаться подальше из-за предосторожности. - person sehe; 25.01.2015