C++ 使用qi::double\uAn qi::uint使用组合立即数=string | float | int规则时std::cout输出中断_

C++ 使用qi::double\uAn qi::uint使用组合立即数=string | float | int规则时std::cout输出中断_,c++,boost-spirit,boost-spirit-qi,C++,Boost Spirit,Boost Spirit Qi,我尝试获取字符串、int和float的即时规则,以便分析以下测试 //strings "\"hello\"", " \" hello \" ", " \" hello \"\"stranger\"\" \" ", //ints "1", "23", "456", //floats "3.3", "34.35" 联机尝试: 使用 而这两个数字完全无法解析 在Coliru下测试,Win7x64 VS2017最新版本,LLVM clang cl 有时,Collir

我尝试获取字符串、int和float的即时规则,以便分析以下测试

 //strings
 "\"hello\"",
 "   \"  hello \"  ",
 "  \"  hello \"\"stranger\"\" \"  ",
 //ints
 "1",
 "23",
 "456",
 //floats
 "3.3",
 "34.35"
联机尝试:

使用

而这两个数字完全无法解析

在Coliru下测试,Win7x64 VS2017最新版本,LLVM clang cl

有时,Colliru会给出太多警告,编译会停止

知道这里发生了什么吗

精神上的警告通常意味着——停在这里,严重损坏的东西

更新:如果我在测试它之前只使用
double
,并且在使用/不使用
uint
解析器时行为发生变化,也会发生这种情况
请尝试:

在整数和双浮点解析器上使用
qi::raw
,以便按词汇转换数字:
qi::raw[qi::uint_]
qi::raw[qi::double_]

但解析的顺序也很重要。如果
uint
解析器在
double
之前,如下所示:

immediate = double_quoted_string | qi::raw[qi::uint_] | qi::raw[qi::double_];
BOOST_SPIRIT_DEBUG_NODES((immediate)); // for debug output
然后,
uint\uu
解析器将部分使用双浮点数,然后整个解析将失败:

<immediate>
  <try>34.35</try>
  <success>.35</success> //<----- this is what is left after uint_ parsed
  <attributes>[[3, 4]]</attributes> // <---- what uint_ parser successfully parsed
</immediate>
"34.35" Failed
Remaining unparsed: "34.35"
“解析”的松散定义是将文本表示转换为“另一种”(通常是更原生的)表示

将一个数字“解析”成std::string是没有意义的。您所看到的是自动属性传播(通过将解析后的数字作为字符粘贴到字符串中)非常努力地理解它

那不是你想要的。相反,您希望解析整数值或双精度值。为此,您可以简单地声明一个变量属性类型:

using V = boost::variant<std::string, double, unsigned int>;
qi::rule<std::string::const_iterator, V()>
    immediate = double_quoted_string | qi::double_ | qi::uint_;
注意
uint\uu
double\u
之后的重新排序。如果首先解析整数,它将解析double的整数部分,直到小数点分隔符,然后解析其余部分失败。更准确地说,您可能希望使用严格的实数解析器,以便只有实数有一个分数的数字才能被解析为双数。这确实限制了整数的范围,因为
无符号整数的范围远远小于
双精度整数的范围

#include <iostream>
#include <iomanip>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;
using namespace std::string_literals;

int main() {
    for (auto&& [str, type] : std::vector {
        std::pair("\"hello\""s,                typeid(std::string).name()),
        {"   \"  hello \"  "s,                 typeid(std::string).name()},
        {"  \"  hello \"\"stranger\"\" \"  "s, typeid(std::string).name()},
        {"1"s,                                 typeid(unsigned int).name()},
        {"23"s,                                typeid(unsigned int).name()},
        {"456"s,                               typeid(unsigned int).name()},
        {"3.3"s,                               typeid(double).name()},
        {"34.35"s,                             typeid(double).name()},
    }) {
        auto iter = str.cbegin(), end = str.cend();

        qi::rule<std::string::const_iterator, std::string()> double_quoted_string
            = '"' >> *("\"\"" >> qi::attr('"') | ~qi::char_('"')) >> '"';

        using V = boost::variant<std::string, double, unsigned int>;
        qi::rule<std::string::const_iterator, V()> immediate
            = double_quoted_string | qi::double_ | qi::uint_;

        std::cout << std::quoted(str) << " ";

        V res;
        bool r = qi::phrase_parse(iter, end, immediate, qi::blank, res);
        bool typecheck = (type == res.type().name());

        if (r) {
            std::cout << "OK: " << res << " typecheck " << (typecheck?"MATCH":"MISMATCH") << "\n";
        } else {
            std::cout << "Failed\n";
        }
        if (iter != end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end)) << "\n";
        }
        std::cout << "----\n";
    }
}
    qi::rule<std::string::const_iterator, V()> immediate
        = double_quoted_string
        | qi::real_parser<double, qi::strict_real_policies<double> >{}
        | qi::uint_;

我仍然对字符串结果可能包含多少原生类型数据感到困惑,相反,我认为Spirits在类型安全性和灵活性之间进行了折衷。你的代码有
std::string res,为了灵活性牺牲了类型安全()。我的版本通过使用变体类型没有任何问题(使用静态多态性保留完整的静态类型,也作为标准化)。如果您不熟悉变量类型,这需要一些时间,但是您很快就会发现它与动态类型非常不同(这更像是)
您的代码有std::string res
,最终它将是所有类型安全的-正如您所展示的那样-目前我只使用string,因为您在示例中已经这样做了
"\"hello\"" OK: 'hello'
----
"   \"  hello \"  " OK: '  hello '
----
"  \"  hello \"\"stranger\"\" \"  " OK: '  hello "stranger" '
----
"1" OK: '1'
----
"64" OK: '64'
----
"456" OK: '456'
----
"3.3" OK: '3.3'
----
"34.35" OK: '34.35'
----
using V = boost::variant<std::string, double, unsigned int>;
qi::rule<std::string::const_iterator, V()>
    immediate = double_quoted_string | qi::double_ | qi::uint_;
#include <iostream>
#include <iomanip>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;
using namespace std::string_literals;

int main() {
    for (auto&& [str, type] : std::vector {
        std::pair("\"hello\""s,                typeid(std::string).name()),
        {"   \"  hello \"  "s,                 typeid(std::string).name()},
        {"  \"  hello \"\"stranger\"\" \"  "s, typeid(std::string).name()},
        {"1"s,                                 typeid(unsigned int).name()},
        {"23"s,                                typeid(unsigned int).name()},
        {"456"s,                               typeid(unsigned int).name()},
        {"3.3"s,                               typeid(double).name()},
        {"34.35"s,                             typeid(double).name()},
    }) {
        auto iter = str.cbegin(), end = str.cend();

        qi::rule<std::string::const_iterator, std::string()> double_quoted_string
            = '"' >> *("\"\"" >> qi::attr('"') | ~qi::char_('"')) >> '"';

        using V = boost::variant<std::string, double, unsigned int>;
        qi::rule<std::string::const_iterator, V()> immediate
            = double_quoted_string | qi::double_ | qi::uint_;

        std::cout << std::quoted(str) << " ";

        V res;
        bool r = qi::phrase_parse(iter, end, immediate, qi::blank, res);
        bool typecheck = (type == res.type().name());

        if (r) {
            std::cout << "OK: " << res << " typecheck " << (typecheck?"MATCH":"MISMATCH") << "\n";
        } else {
            std::cout << "Failed\n";
        }
        if (iter != end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end)) << "\n";
        }
        std::cout << "----\n";
    }
}
"\"hello\"" OK: hello typecheck MATCH
----
"   \"  hello \"  " OK:   hello  typecheck MATCH
----
"  \"  hello \"\"stranger\"\" \"  " OK:   hello "stranger"  typecheck MATCH
----
"1" OK: 1 typecheck MISMATCH
----
"23" OK: 23 typecheck MISMATCH
----
"456" OK: 456 typecheck MISMATCH
----
"3.3" OK: 3.3 typecheck MATCH
----
"34.35" OK: 34.35 typecheck MATCH
----
    qi::rule<std::string::const_iterator, V()> immediate
        = double_quoted_string
        | qi::real_parser<double, qi::strict_real_policies<double> >{}
        | qi::uint_;
"\"hello\"" OK: hello typecheck MATCH
----
"   \"  hello \"  " OK:   hello  typecheck MATCH
----
"  \"  hello \"\"stranger\"\" \"  " OK:   hello "stranger"  typecheck MATCH
----
"1" OK: 1 typecheck MATCH
----
"23" OK: 23 typecheck MATCH
----
"456" OK: 456 typecheck MATCH
----
"3.3" OK: 3.3 typecheck MATCH
----
"34.35" OK: 34.35 typecheck MATCH
----