【问题标题】:boost.spirit compilation error : cannot convert argument 1 from "const char * " to "std::_String_iterator<std::_String_val>boost.spirit 编译错误:无法将参数 1 从“const char *”转换为“std::_String_iterator<std::_String_val>
【发布时间】:2016-04-14 03:45:51
【问题描述】:

我正在尝试使用 boost.spirit 库为 csv 文件编写解析器。我遇到以下编译错误。我是 boost.spirit 的新手,有人能找出原因吗?

错误信息是:

错误 C2664: 'bool boost::spirit::qi::rule::parse(Iterator &,const Iterator &,Context &,const Skipper &,Attribute &) const': 无法从 'const char 转换参数 1 *' 到 '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;
};

代码确实是从Simplest way to read a CSV file mapped to memory? 采用的,所以我没有任何线索。我正在使用 Microsoft Visual Studio 2015 和 boost 1.16.0。

如果我将typedef boost::string_ref CsvField 替换为typedef std::string,或将字段解析器替换为field = *(~char_(",\r\n")),则会出现同样的错误。

另外,我正在解析的文件实际上是一个标准的 csv 文件,因此欢迎提出其他解析方法的建议。唯一的问题是该文件有数百万行,因此标准的逐行解析对我不起作用。

【问题讨论】:

    标签: c++ parsing csv boost boost-spirit


    【解决方案1】:

    您没有显示相关代码。您所拥有的只是一个模板类,但任何实例化是否格式正确都取决于您实例化它的方式。

    现在我假设您正在尝试使用 std::string::const_iterator 作为迭代器类型进行实例化 - 这有点有趣 w.r.t.提到内存映射和 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&amp;。我将把它作为练习留给读者。

    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
    

    【讨论】:

      猜你喜欢
      • 2014-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多