您过多地使用命名空间。此外,ADL 会为 std::string 参数引入 std::ref,除非 ref 带有括号或命名空间限定。
过度使用using namespace 绝不是一个好主意(参见例如Why is "using namespace std;" considered bad practice?),在这种情况下,消息说明了std::ref 和boost::phoenix::ref 之间的混淆(可能还有其他人,但你没有' t 包括完整的消息)。
说不:
Live On Coliru
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/optional.hpp>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
#define addMinorProblem(...) do {} while (0)
boost::optional<std::pair<double, std::string>> parse(std::string_view input)
{
using Iterator = std::string_view::const_iterator;
Iterator first = begin(input), last = end(input);
double duration;
std::string title;
boost::spirit::qi::rule<Iterator, std::string()> quoutedString;
quoutedString %= qi::lexeme[+(qi::char_)];
bool r = parse(first, last,
("#EXTINF:" >> qi::double_[px::ref(duration) = qi::_1] >>
-(',' >> quoutedString[px::ref(title) = qi::_1])));
if (!r || first != last) {
addMinorProblem(stateObj,
_("Cannot parse information from #EXTINF tag"));
return {};
}
return std::make_pair(duration, title);
}
int main()
{
for (std::string const input : {
"#EXTINF:10,Title of the segment", // => I need "Title of the
// segment" phrase
"#EXTINF:20,Title", // => I need "Title" phrase
"#EXTINF:12", // => I need "" phrase
}) {
if (auto result = parse(input)) {
std::cout << "Parsed: (" << result->first << ", " << std::quoted(result->second) << ")\n";
} else {
std::cout << "Cannot parse " << std::quoted(input) << "\n";
}
}
}
打印
Parsed: (10, "Title of the segment")
Parsed: (20, "Title")
Parsed: (12, "")
改进,小事
-
通过一些明智的 local using 声明,您可以再次使其“更短”:
using namespace qi::labels;
using px::ref;
bool r = parse(first, last,
("#EXTINF:" >> qi::double_[ref(duration) = _1] >>
-(',' >> quoutedString[(ref)(title) = _1])));
我个人觉得这更晦涩难懂(想象自己在代码审查中解释(ref)(title)?)
-
operator %= 没有语义操作是没有意义的
-
qi::lexeme[] 没有船长就毫无意义(见Boost spirit skipper issues)
-
quoutedString [sic] 用词不当(现在?),因为它不解析引号
-
为什么不使用自动属性传播而不是痛苦的语义操作?它们只会增加编译时间,而且,正如您所发现的,还会增加开发时间。见Boost Spirit: "Semantic actions are evil"?
-
另外,与其在解析后繁琐地检查first == last,不如简单地匹配表达式中的>> qi::eoi?
以上所有内容都简化为以下内容:
Live On Coliru
boost::optional<std::pair<double, std::string>> parse(std::string_view input)
{
namespace qi = boost::spirit::qi;
double duration;
std::string title;
if (qi::parse(
begin(input), end(input), //
("#EXTINF:" >> qi::double_ >> -(',' >> +qi::char_) >> qi::eoi),
duration, title))
{
return std::make_pair(duration, title);
}
addMinorProblem(stateObj, _("Cannot parse information from #EXTINF tag"));
return {};
}
没有更多phoenix,语义操作,什么不是。仍在打印:
Parsed: (10, "Title of the segment")
Parsed: (20, "Title")
Parsed: (12, "")