问题是使用auto
表达式来捕获规则,从解析器表达式推导出类型。该类型是一个原始表达式树,它通过引用捕获任何关系,但这意味着许多中间体在封闭的结束后就消失了充分表达 http://eel.is/c++draft/intro.execution#def:full-expression (see C++:临时参数的寿命? https://stackoverflow.com/questions/2506793/c-life-span-of-temporary-arguments).
这是众所周知的,正如您在这里看到的:
- 将解析器分配给自动变量 https://stackoverflow.com/questions/22023779/assigning-parsers-to-auto-variables/22027181#22027181
- boost Spirit V2 qi 与优化级别相关的错误 https://stackoverflow.com/questions/20763665/boost-spirit-v2-qi-bug-associated-with-optimization-level/20766909#20766909
- boost::spirit::qi::phrase_parse 中某处未定义的行为 https://stackoverflow.com/questions/26410498/undefined-behaviour-somewhere-in-boostspiritqiphrase-parse
- 还有更多
这是最简单的修复:
auto versionParser = bsq::copy(
bsq::uint_
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_));
If you also fix缺少局部变量的初始化它可以正常工作:
Live On Coliru http://coliru.stacked-crooked.com/a/fd704b7026c7fb3e
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>
namespace bsq = boost::spirit::qi;
int main()
{
std::cout << "BOOST_VERSION: " << BOOST_VERSION << std::endl;
std::uint16_t major = 0, minor = 0, build = 0, revision = 0;
auto versionParser = bsq::copy(
bsq::uint_
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_)
>> -('.' >> bsq::uint_));
std::string version = "3.5.1";
auto start = version.begin();
if (!bsq::parse(start, version.end(), versionParser, major, minor, build, revision))
{
std::cout << "Error!\n";
}
std::cout << major << "-" << minor << "-" << build << "-" << revision << std::endl;
}
Prints
BOOST_VERSION: 106600
3-5-1-0
补充笔记
-
为了避免整个“统一属性”的情况,让解析器分配给所有元素,即使在输入文本中未指定:
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
-
诊断存在尾随“垃圾”的错误(例如"3.4bogus"
),您可以添加一个检查来检查完整的输入是否被解析:
auto versionParser = bsq::copy(
bsq::uint_
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> bsq::eoi);
-
因为版本在语义上是一个元组,为什么不这样表示它呢?
using Version = std::tuple<uint16_t, uint16_t, uint16_t, uint16_t>;
Version parsed;
if (!bsq::parse(version.begin(), version.end(), versionParser, parsed))
std::cout << "Error!\n";
这样你甚至可以说:
using boost::fusion::operator<<;
auto obsolete = parsed < Version(3, 4, 0, 0);
std::cout << "Version " << parsed << " " << (obsolete? "too old" : "supported") << "\n";
结合这些:
Live On Coliru http://coliru.stacked-crooked.com/a/64b16260c559556e
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/spirit/include/qi.hpp>
namespace bsq = boost::spirit::qi;
int main() {
auto versionParser = bsq::copy(
bsq::uint_
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> ('.' >> bsq::uint_ | bsq::attr(0))
>> bsq::eoi);
std::string version = "3.5.1";
using Version = std::tuple<uint16_t, uint16_t, uint16_t, uint16_t>;
Version parsed;
if (!bsq::parse(version.begin(), version.end(), versionParser, parsed))
std::cout << "Error!\n";
using boost::fusion::operator<<;
auto obsolete = parsed < Version(3, 4, 0, 0);
std::cout << "Version " << parsed << " " << (obsolete? "too old" : "supported") << "\n";
}
Prints
Version (3 5 1 0) supported
std::tuple
sucks?
我同意。因此,等效地编写您自己的结构:
Live On Coliru http://coliru.stacked-crooked.com/a/86b37d7460bd6db1
struct Version {
uint16_t major, minor, revision, build;
auto key() const { return std::tie(major, minor, revision, build); }
bool operator<(Version const& b) const { return key() < b.key(); }
};
BOOST_FUSION_ADAPT_STRUCT(Version, major, minor, revision, build)
与时俱进
请注意,Spirit X3(进入振奋精神;齐还是X3? https://stackoverflow.com/questions/52990661/getting-into-boost-spirit-qi-or-x3/52991170#52991170) 没有auto
-您遇到的问题:
Live On Coliru http://coliru.stacked-crooked.com/a/93a33781789224ea
#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/io.hpp>
#include <iostream>
namespace bsx = boost::spirit::x3;
struct Version {
uint16_t major, minor, revision, build;
auto key() const { return std::tie(major, minor, revision, build); }
bool operator<(Version const& b) const { return key() < b.key(); }
};
BOOST_FUSION_ADAPT_STRUCT(Version, major, minor, revision, build)
int main() {
auto versionParser = bsx::uint_
>> ('.' >> bsx::uint_ | bsx::attr(0))
>> ('.' >> bsx::uint_ | bsx::attr(0))
>> ('.' >> bsx::uint_ | bsx::attr(0))
>> bsx::eoi;
std::string version = "3.5.1";
Version parsed;
if (!parse(version.begin(), version.end(), versionParser, parsed))
std::cout << "Error!\n";
using boost::fusion::operator<<;
auto obsolete = parsed < Version{3, 4, 0, 0};
std::cout << "Version " << parsed << " " << (obsolete? "too old" : "supported") << "\n";
}
打印也一样。