【问题标题】:Parsing a boost::variant with User Defined Datatype containing std::string using Spirit Qi使用 Spirit Qi 解析包含 std::string 的用户定义数据类型的 boost::variant
【发布时间】:2015-05-27 05:16:07
【问题描述】:

我正在尝试使用 Spirit.Qi 创建一个 GPIB 解析器。有时响应可以 要么是错误,要么是正常响应。这似乎是一个很好的用例 产生boost::variant的替代解析器;但是,如果其中之一 变体类型包含代码无法编译的字符串。这是一个简化的 重现错误的版本。

struct C1 {
   std::string h{""};
   int i{0};
};
BOOST_FUSION_ADAPT_STRUCT(C1, (std::string, h)(int, i))

struct C2 {
   std::string h{""};
   std::string c{};
};
BOOST_FUSION_ADAPT_STRUCT(C2, (std::string, h)(std::string, c))

using VariantType = boost::variant<C1, C2>;

int main() {
   std::string s2{"C2:Zoo3"};
   VariantType v1;
   if(qi::parse(s1.begin(), s1.end(), 
                (qi::string("C1") >> ":" >> qi::int_) | 
                (qi::string("C2") >> ":" >> *qi::char_), 
                v1)) {
      if(boost::get<C1>(&v1)) {
         auto a1 = boost::get<C1>(v1);
         std::cout << "Parsing Succeeded, a1 = " << a1.h << ":" 
                   << a1.i << std::endl;
      }
      else {
         auto a2 = boost::get<C2>(v1);
         std::cout << "Parsing Succeeded, a2 = " << a2.h << ":" 
                   << a2.c << std::endl;
      }
   }
   else {
      std::cout << "Parsing Failed" << std::endl;
   }
   return 0;
}

除了*qi::char_(例如qi::string)之外,我已经尝试过各种解析器,但均无济于事。如果我将 C2::c 更改为 char 它适用于 1 个字符。到目前为止,我发现的最佳解决方法是将C2::c 更改为std::vector&lt;char&gt;,这可以正常工作但并不理想。我还尝试告诉 Qi std::string 是一个类似于 here 的容器。但是qi知道std::string是什么,所以我很确定它忽略了我的自定义。我认为这完全是因为 std::string 不是 POD 并且在规则放松之前不受联合的支持,但是当它不在结构中时它可以与 boost::variant 一起使用,并且 std::vector 可以使用。任何想法/解决方法将不胜感激。

*注意:我没有发布编译器错误,因为它们很长且被破坏,我认为这是std::string 和变体的已知问题。如果他们有帮助,请告诉我,我会发布。

【问题讨论】:

  • Qi 知道什么是字符串,所以自定义是多余的:coliru.stacked-crooked.com/a/508941b22ad5bc1d。 POD-ness 当然不是必需的(Boost Variant 的目的是什么?)。 (不要打电话给variants 工会,这会造成不必要的混乱。)

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


【解决方案1】:

据我所知,代码没有任何问题。

我使用 gcc {4.9,5.x} 和 clang++ 3.5 在 c++1{1,4,y} 和 boost 1.{57,58}.0 上进行了测试。

我怀疑你可能有一个尴尬的 Boost 版本。尝试在那里使用qi::as_string[*qi::char_]。 ¹

Live On Coliru

#include <iostream>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

struct C1 {
   std::string h{""};
   int i{0};

   friend std::ostream& operator<<(std::ostream& os, C1 const& c1) {
       return os << "C1 {h:'" << c1.h << "', i:'" << c1.i << "'}";
   }
};

struct C2 {
   std::string h{""};
   std::string c{};

   friend std::ostream& operator<<(std::ostream& os, C2 const& c2) {
       return os << "C2 {h:'" << c2.h << "', c:'" << c2.c << "'}";
   }
};

BOOST_FUSION_ADAPT_STRUCT(C1, (std::string, h)(int, i))
BOOST_FUSION_ADAPT_STRUCT(C2, (std::string, h)(std::string, c))

using VariantType = boost::variant<C1, C2>;
namespace qi = boost::spirit::qi;

int main() {
    VariantType value;
    for(std::string s1 : {
            "C2:Zoo3",
            "C1:1234"
            })
    {
        if(qi::parse(s1.begin(), s1.end(), 
                    (qi::string("C1") >> ":" >> qi::int_) | 
                    (qi::string("C2") >> ":" >> *qi::char_), 
                    value)) 
            std::cout << "Parsing Succeeded: " << value << "\n";
        else             
            std::cout << "Parsing Failed" << std::endl;
    }
}

打印

Parsing Succeeded: C2 {h:'C2', c:'Zoo3'}
Parsing Succeeded: C1 {h:'C1', i:'1234'}

¹我不推荐 qi::attr_cast&lt;&gt;,因为我记得这在笨拙的旧 boost 版本中有一个尴尬的错误。

【讨论】:

  • 这里甚至是with g++-4.6 -std=c++03
  • 谢谢。您的代码有效,实际上我的代码也有效。我发布的代码是 4 个测试用例之一。在我自己尝试之后它工作了,所以我仍然不确定问题是什么。我需要更多地研究它。我很抱歉没有测试我发布的代码,这是粗心的。由于我看到的所有奇怪现象,我说服自己这与联合和字符串有关。我也在使用 gcc 4.9.2 (work) 5.1 (home) 和 boost 1.58。感谢您的快速回复,我非常感谢您对 SO 的贡献。您的回复让我知道这是可行的。
猜你喜欢
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 2021-06-06
  • 1970-01-01
  • 1970-01-01
  • 2017-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多