调用 lambda 的语义操作

Semantic actions calling lambda

我正在尝试使用 boost spirit 解析时间字符串,但不确定为什么这不起作用。

auto fill_ts_nanos = [&t] (int h, int m, int s, int ms) -> int
                                { t.tv_nsec = ( ( h * 3600 + m * 60 + s ) * 1000 + ms ) * 1000000; return t.tv_sec; };
auto fill_suffix   = [&suffix] (string &s) { suffix=s; };

auto parse_ok = qi::parse(input.begin(), input.end(),
               ( qi::int_ >> qi::char_(":") >> qi::int_ >> qi::char_(":") >> 
                 qi::int_ >> qi::char_(".") >> qi::int_ ) 
                 [boost::bind(fill_ts_nanos, qi::_1, qi::_3, qi::_5, qi::_7                
                >> qi::char_(",") >> qi::as_string[*qi::char_][fill_suffix]  ;

示例输入为“04:00:00.512,2251812698588658”

在猜测了很多细节之后(例如 t 的类型应该是什么),这里是带有一些调试输出的固定代码:

Live On Coliru

Note: I fixed the signed-ness of the numbers as well as I changed the types to prevent overflow.

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <ctime>
#include <chrono>
#include <iomanip>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using namespace std::chrono_literals;
using namespace qi::labels;

int main() {
    timespec t;
    std::string suffix;

    auto fill_ts_nanos = [&t](int h, unsigned m, unsigned s, unsigned ms) -> long {
        t = {};
        t.tv_nsec = ((h * 3600 + m * 60 + s) * 1000 + ms) * 1000000l;
        return t.tv_sec;
    };

    auto fill_suffix = [&suffix](std::string &s) { suffix = s; };

    std::string const input = "04:00:00.512,2251812698588658";

    auto parse_ok = qi::parse(input.begin(), input.end(),
               (qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_) 
                 [px::bind(fill_ts_nanos, _1, _2, _3, _4) ]
                >> ',' >> qi::as_string[*qi::char_]
                 [fill_suffix] );

    std::printf("%lld.%.9ld\n", (long long)t.tv_sec, t.tv_nsec);

    auto ns = t.tv_nsec * 1ns;

    std::cout << std::fixed << std::setprecision(6);
    std::cout << "hours: " << (ns / 1.0h) << "\n";
    std::cout << "minutes: " << (ns / 1.0min) << "\n";
    std::cout << "seconds: " << (ns / 1.0s) << "\n";

    std::cout << "suffix: " << suffix << "\n";

    return parse_ok? 0:255;
}

版画

0.14400512000000
hours: 4.000142
minutes: 240.008533
seconds: 14400.512000
suffix: 2251812698588658

建议

我会尽量简化它,例如,通过创建规则:

qi::rule<It, long()> timespec_ = 
       (qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_) 
       [ _val = ((_1 * 3600 + _2 * 60 + _3) * 1000 + _4) * 1000000l ];

这意味着您可以只解析:

timespec t {};
std::string suffix;

It f = input.begin(), l = input.end();

parse(f, l, timespec_ >> ',' >> *qi::char_, t.tv_nsec, suffix);

这具有相同的输出:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <ctime>
#include <chrono>
#include <iomanip>

namespace qi = boost::spirit::qi;
namespace px = boost::phoenix;
using namespace std::chrono_literals;
using namespace qi::labels;

using It = std::string::const_iterator;

qi::rule<It, long()> timespec_ = 
       (qi::int_ >> ':' >> qi::uint_ >> ':' >> qi::uint_ >> '.' >> qi::uint_) 
       [ _val = ((_1 * 3600 + _2 * 60 + _3) * 1000 + _4) * 1000000l ];

int main() {
    std::string const input = "04:00:00.512,2251812698588658";

    timespec t {};
    std::string suffix;

    It f = input.begin(), l = input.end();

    if (parse(f, l, timespec_ >> ',' >> *qi::char_, t.tv_nsec, suffix)) {
        std::printf("%lld.%.9ld\n", (long long)t.tv_sec, t.tv_nsec);

        auto ns = t.tv_nsec * 1ns;

        std::cout << std::fixed << std::setprecision(6);
        std::cout << "hours: " << (ns / 1.0h) << "\n";
        std::cout << "minutes: " << (ns / 1.0min) << "\n";
        std::cout << "seconds: " << (ns / 1.0s) << "\n";

        std::cout << "suffix: " << suffix << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

    if (f!=l) {
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
    }
}

无奈之下,我也弄清楚了容器版本的工作原理。见下文,

auto test_fn = [&t](auto c) {
            t.tv_nsec = ( ( at_c<0>(c) * 3600 + 
                            at_c<2>(c)  * 60  + 
                            at_c<4>(c)  ) * 1000 + 
                            at_c<6>(c)  ) * 1000000; 

auto parse_ok = qi::parse(input.begin(), input.end(),
              ( qi::int_ >> qi::char_(":") >> qi::int_ >> qi::char_(":") >> 
                qi::int_ >> qi::char_(".") >> qi::int_ )[ test_fn ]

不可否认,它很丑。