使用 Spirit Qi 解析包含 std::string 的用户定义数据类型的 boost::variant
Parsing a boost::variant with User Defined Datatype containing std::string using Spirit Qi
我正在尝试使用 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<char>
,这工作正常但并不理想。我也试着告诉 Qi std::string
是一个像 here 这样的容器。但是 qi 知道 std::string
是什么,所以我很确定它会忽略我的自定义。我认为这都是因为 std::string
不是 POD,并且在放宽规则之前不受联合支持,但是当它不在结构中时它可以与 boost::variant
一起使用,并且 std::vector
有效。任何 ideas/workarounds 将不胜感激。
*注意:我没有 post 编译器错误,因为它们又长又乱,我认为这是 std::string
和变体的已知问题。如果他们有帮助,请告诉我,我会 post 他们。
据我所知,代码没有任何问题。
我已经在 c++1{1,4,y} 和 boost 1.{57,58}.0 上使用 gcc {4.9,5.x} 和 clang++ 3.5 进行了测试。
我怀疑您的 Boost 版本可能很笨拙。尝试在那里使用 qi::as_string[*qi::char_]
。 ¹
#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<>
因为我记得这在笨拙的旧提升版本中有一个尴尬的错误。
我正在尝试使用 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<char>
,这工作正常但并不理想。我也试着告诉 Qi std::string
是一个像 here 这样的容器。但是 qi 知道 std::string
是什么,所以我很确定它会忽略我的自定义。我认为这都是因为 std::string
不是 POD,并且在放宽规则之前不受联合支持,但是当它不在结构中时它可以与 boost::variant
一起使用,并且 std::vector
有效。任何 ideas/workarounds 将不胜感激。
*注意:我没有 post 编译器错误,因为它们又长又乱,我认为这是 std::string
和变体的已知问题。如果他们有帮助,请告诉我,我会 post 他们。
据我所知,代码没有任何问题。
我已经在 c++1{1,4,y} 和 boost 1.{57,58}.0 上使用 gcc {4.9,5.x} 和 clang++ 3.5 进行了测试。
我怀疑您的 Boost 版本可能很笨拙。尝试在那里使用 qi::as_string[*qi::char_]
。 ¹
#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<>
因为我记得这在笨拙的旧提升版本中有一个尴尬的错误。