【发布时间】:2016-02-22 08:23:04
【问题描述】:
你能帮我理解a % b 解析器和它在Boost.Spirit 中的扩展a >> *(b >> a) 形式之间的区别吗?尽管the reference manual 声明它们是等价的,
列表运算符
a % b是一个二元运算符,它匹配一个或多个重复的a的列表,由b的出现分隔。这相当于a >> *(b >> a)。
以下程序根据使用的不同产生不同的结果:
#include <iostream>
#include <string>
#include <vector>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
struct Record {
int id;
std::vector<int> values;
};
BOOST_FUSION_ADAPT_STRUCT(Record,
(int, id)
(std::vector<int>, values)
)
int main() {
namespace qi = boost::spirit::qi;
const auto str = std::string{"1: 2, 3, 4"};
const auto rule1 = qi::int_ >> ':' >> (qi::int_ % ',') >> qi::eoi;
const auto rule2 = qi::int_ >> ':' >> (qi::int_ >> *(',' >> qi::int_)) >> qi::eoi;
Record record1;
if (qi::phrase_parse(str.begin(), str.end(), rule1, qi::space, record1)) {
std::cout << record1.id << ": ";
for (const auto& value : record1.values) { std::cout << value << ", "; }
std::cout << '\n';
} else {
std::cerr << "syntax error\n";
}
Record record2;
if (qi::phrase_parse(str.begin(), str.end(), rule2, qi::space, record2)) {
std::cout << record2.id << ": ";
for (const auto& value : record2.values) { std::cout << value << ", "; }
std::cout << '\n';
} else {
std::cerr << "syntax error\n";
}
}
1: 2, 3, 4,
1: 2,
rule1 和 rule2 的不同之处仅在于 rule1 使用列表运算符 ((qi::int_ % ',')) 和 rule2 使用其扩展形式 ((qi::int_ >> *(',' >> qi::int_)))。然而,rule1 产生了1: 2, 3, 4,(如预期的那样),rule2 产生了1: 2,。我无法理解rule2 的结果:1)为什么它不同于rule1 和2)为什么3 和4 不包含在record2.values 中,即使phrase_parse 以某种方式返回true?
【问题讨论】:
-
有幸记住圣灵术语的人可以更好地解释它,但它们在匹配的内容上看起来相当,但在他们接受用于存储值的类型上却不一样。第二个似乎适用于
(int, int, vector<int>)而不是(int, vector<int>)。我猜vector<int>与单个int_兼容,然后在存储值时会忽略重复的int_s(在*(…)内)。 -
是的,就是这样,看看我的回答@chris。但是代码中有一个大错误,所以就是这样(任何事情都可能发生)
-
@sehe,谢谢,我对 Spirit 很感兴趣,但我还没有机会使用它。 CppCon X3 的演讲非常酷。
-
@chris 这促使我在 Spirit X3 中做相应的测试用例。正如预期的那样,总体上情况要好得多(没有 UB,没有静默属性传播失败,更不用说大大提高了编译时间 :))。见我的second answer
-
另一个区别是,如果
b有一个属性(在您的示例中不是这种情况),它会在a%b中被忽略,但在a >>*(b >> a)中不会被忽略。a >> *(omit[b] >> a)会更接近(但与sehe的答案中显示的问题相同)。
标签: c++ boost boost-spirit boost-spirit-qi