Ошибка компиляции boost.spirit: невозможно преобразовать аргумент 1 из const char * в "std :: _ String_iterator‹ std :: _ String_val ›

Я пытаюсь написать парсер для файла csv, используя библиотеку boost.spirit. Я обнаружил следующую ошибку компиляции. Я новичок в boost.spirit, может кто-нибудь определить причины?

Сообщение об ошибке:

Ошибка C2664: 'bool boost :: spirit :: qi :: rule :: parse (Iterator &, const Iterator &, Context &, const Skipper &, Attribute &) const': невозможно преобразовать аргумент 1 из 'const char *' в 'std :: _ String_iterator >> &'

И мой код:

#pragma once
#define BOOST_SPIRIT_USE_PHOENIX_V3

#include<vector>
#include<string>
#include<memory>
#include<boost/iostreams/device/mapped_file.hpp> // for mmap
#include<boost/utility/string_ref.hpp>
#include<boost/spirit/include/qi.hpp>
#include<boost/spirit/include/qi_grammar.hpp>
#include<boost/spirit/include/qi_real.hpp>
#include<boost/spirit/include/phoenix.hpp>
#include<boost/spirit/include/qi_symbols.hpp>

typedef boost::string_ref CsvField;
typedef std::vector<CsvField> CsvLine;
typedef std::vector<CsvLine> CsvFile; 
namespace qi = boost::spirit::qi;

template <typename T> struct CsvParser : qi::grammar<T, CsvFile()> {
    CsvParser() : CsvParser::base_type(lines) {
        using namespace qi;
        using boost::phoenix::construct;
        using boost::phoenix::size;
        using boost::phoenix::begin;
        using boost::spirit::qi::float_;

        field = raw[*~char_(",\r\n")][_val = construct<CsvField>(begin(qi::_1), size(qi::_1))]; // semantic action
        //field = qi::float_;
        line = field % ',';
        lines = line  % eol;
    }
    // declare: line, field, fields
    qi::rule<T, CsvFile()> lines;
    qi::rule<T, CsvLine()> line;
    qi::rule<T, CsvField()> field;
};

Код действительно заимствован из Простейший способ прочитать CSV-файл, сопоставленный с памятью?, поэтому я понятия не имею. Я использую Microsoft Visual Studio 2015 и буст 1.16.0.

Эта же ошибка возникает, если я заменяю typedef boost::string_ref CsvField на typedef std::string или заменяю синтаксический анализатор поля на field = *(~char_(",\r\n")).

Кроме того, файл, который я анализирую, на самом деле является стандартным файлом CSV, поэтому любые предложения об альтернативных методах анализа приветствуются. Единственная загвоздка в том, что в файле миллионы строк, поэтому стандартный построчный синтаксический анализ у меня не работает.


person Chandler    schedule 14.04.2016    source источник


Ответы (1)


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

Прямо сейчас я предполагаю, что вы пытаетесь создать экземпляр с std::string::const_iterator в качестве типа итератора - что немного забавно с. упоминание отображения памяти и string_ref (что подразумевает, что вы хотите делать все с нулевым копированием).

Тем не менее, проблема в том, что raw[] предоставляет диапазон iterator_range исходного типа итератора, то есть вы передаете std::string::const_iterator в качестве первого аргумента конструктора string_ref (псевдоним CsvField). Это не сработает.

В исправлении:

field = raw[*~char_(",\r\n")][_val = construct<CsvField>(&*begin(qi::_1), size(qi::_1))]; // semantic action

Чтобы быть действительно милым, вы должны заключить std::addressof в актера-феникса и использовать его вместо operator&. Я оставлю это читателю в качестве упражнения.

Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include<boost/utility/string_ref.hpp>
#include<boost/spirit/include/qi.hpp>
#include<boost/spirit/include/phoenix.hpp>

typedef boost::string_ref CsvField;
typedef std::vector<CsvField> CsvLine;
typedef std::vector<CsvLine> CsvFile; 

namespace qi = boost::spirit::qi;

template <typename T> struct CsvParser : qi::grammar<T, CsvFile()> {
    CsvParser() : CsvParser::base_type(lines) {
        using namespace qi;
        using boost::phoenix::construct;
        using boost::phoenix::size;
        using boost::phoenix::begin;
        using boost::spirit::qi::float_;

        field = raw[*~char_(",\r\n")][_val = construct<CsvField>(&*begin(qi::_1), size(qi::_1))]; // semantic action
        //field = qi::float_;
        line = field % ',';
        lines = line  % eol;
    }
    // declare: line, field, fields
    qi::rule<T, CsvFile()> lines;
    qi::rule<T, CsvLine()> line;
    qi::rule<T, CsvField()> field;
};

int main()
{
    using It = std::string::const_iterator;
    CsvParser<It> p;

    std::string const input = R"([section1]
key1=value1
key2=value2
[section2]
key3=value3
key4=value4
)";

    CsvFile parsed;
    auto f = input.begin(), l = input.end();
    bool ok = parse(f, l, p, parsed);

    if (ok) {
        std::cout << "Parsed: " << parsed.size() << " stuffs\n";
    } else {
        std::cout << "Parse failed\n";
    }

    if (f != l)
        std::cout << "Remaining input: '" << std::string(f, l) << "'\n";
}

Печать:

Parsed: 7 stuffs
person sehe    schedule 14.04.2016