【问题标题】:strange error with boost::spirit::position_iterator2boost::spirit::position_iterator2 的奇怪错误
【发布时间】:2012-12-22 18:11:02
【问题描述】:

所以我要做的是解析一个字符串列表:

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

std::string TEST = "aa\nbbbb\nccc\n";

std::istringstream INPUT (TEST);
std::noskipws(INPUT);

typedef std::istreambuf_iterator<char> base_iterator;
typedef boost::spirit::multi_pass<base_iterator>  multi_pass_iter;
typedef boost::spirit::classic::position_iterator2<multi_pass_iter> pos_iterator;

base_iterator base_begin(INPUT);

multi_pass_iter first =  boost::spirit::make_default_multi_pass(base_begin);
multi_pass_iter last;

pos_iterator pfirst(first,last,std::string("DD"));
pos_iterator plast;

using qi::lexeme;
using ascii::alpha;

std::vector<std::string> DDD;
bool res = qi::phrase_parse(pfirst,plast,* lexeme[+alpha],ascii::space,DDD);

for (const auto & d : DDD) std::cout << d << " (" << d.size() << ")" << std::endl;

我在DDD 中得到的是 3 个大小正确的字符串,但都是空格。

如果我改用

bool res = qi::phrase_parse(first,last,* lexeme[+alpha],ascii::space,DDD);

一切都按预期进行。 我过去使用position_iterator2 没有任何问题,所以我不认为这是一个错误。我错过了什么吗?

【问题讨论】:

  • 你真的需要 boost::spirit 来拆分字符串吗?
  • @maverik 我刚刚将问题与一个更大的项目隔离开来。
  • for 在函数外无效。

标签: c++ boost-spirit boost-spirit-qi


【解决方案1】:

我想这是a Spirit bug。如果您查看ticket 的底部,您会发现我认为可以修复它的补丁。

【讨论】:

  • 谢谢戴夫,这是一个相关的补充。 (我很好奇它现在是否实际上与 VC++ 结合使用...)
【解决方案2】:

有一个示例here 也不起作用。使用 Visual Studio 2012 都会发出警告:

boost/iterator/iterator_adaptor.hpp(306): warning C4172: returning address of local variable or temporary
boost_1_52_0\boost/iterator/iterator_adaptor.hpp(306) : while compiling class template member function 'const char &boost::iterator_adaptor<Derived,Base,Value,Traversal>::dereference(void) const'
         with
         [
            Derived=boost::spirit::classic::position_iterator2<forward_iterator_type>,
            Base=forward_iterator_type,
            Value=const char,
            Traversal=boost::forward_traversal_tag
         ]

在 Google 上快速搜索“iterator_adaptor dereferencetemporary”会导致 this 建议 iterator_adaptorReference 参数为非引用类型。

为了实现这一点,您需要更改文件“boost/spirit/home/classic/iterator/impl/position_iterator.ipp”。具体来说,您需要更改:

typedef boost::iterator_adaptor<
    main_iter_t,
    ForwardIterT,
    const_value_type,
    boost::forward_traversal_tag
> type;

到:

typedef boost::iterator_adaptor<
    main_iter_t,
    ForwardIterT,
    const_value_type,
    boost::forward_traversal_tag,
    const_value_type
> type;

这会导致 g++ 和 vc11 出现新错误:

boost_1_52_0\boost/concept_check.hpp(212): error C2440: 'initializing' : cannot convert from 'boost::detail::iterator_category_with_traversal<Category,Traversal>' to 'std::forward_iterator_tag'
          with
          [
              Category=std::input_iterator_tag,
              Traversal=boost::forward_traversal_tag
          ]
          No constructor could take the source type, or constructor overload resolution was ambiguous

如果将iterator_adaptor typedef 更改为:

typedef boost::iterator_adaptor<
    main_iter_t,
    ForwardIterT,
    const_value_type,
    std::forward_iterator_tag,
    const_value_type
> type;

这使得下面的程序(基于您的代码)和 boost-spirit.com 中的示例都可以工作,但我不确定它在其他情况下是否会中断,因此请自行决定使用它。

#include <vector>
#include <istream>
#include <sstream>
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/spirit/include/classic_position_iterator.hpp>

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

int main()
{

    std::string TEST = "aa\nbbbb\nccc\n";

    std::istringstream INPUT (TEST);
    std::noskipws(INPUT);

    typedef std::istreambuf_iterator<char> base_iterator;
    typedef boost::spirit::multi_pass<base_iterator>  multi_pass_iter;
    typedef boost::spirit::classic::position_iterator2<multi_pass_iter> pos_iterator;

    base_iterator base_begin(INPUT);

    multi_pass_iter first =  boost::spirit::make_default_multi_pass(base_begin);
    multi_pass_iter last;

    pos_iterator pfirst(first,last,std::string("DD"));
    pos_iterator plast;

    using qi::lexeme;
    using ascii::alpha;

    std::vector<std::string> DDD;
    bool res = qi::phrase_parse(pfirst,plast,* lexeme[+alpha],ascii::space,DDD);

    if(res && pfirst==plast)
    {
        for (const auto & d : DDD) 
            std::cout << d << " (" << d.size() << ")" << std::endl;
    }
    else
    {
        std::cout << "Parsing error." << std::endl;
    }

    return 0;
}

【讨论】:

  • 谢谢,我试试(并报告错误)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多