有没有一种简单的方法可以使 std::chrono::duration 的单位可配置?

问题描述 投票:0回答:1

我试图通过修改由 boost::property_tree 解析的 xml 配置文件来设置报告 std::chrono::duration 的单位。我当前的非编译解决方案尝试使用 std::variant 来执行此操作。

在.hpp类声明中

using TimestampVariant = std::variant<
        std::chrono::nanoseconds, 
        std::chrono::microseconds,
        std::chrono::milliseconds,
        std::chrono::seconds
    >; 

TimestampVariant _timestamp_v;

在.cpp中

auto GetTimestampVisitor =  [](const auto& t) -> decltype(auto) {
    return std::chrono::duration_cast<std::remove_reference_t<decltype(t)>>(std::chrono::system_clock::now().time_since_epoch()).count(); 
};

void SetupFunction()
{
    boost::property_tree::ptree property_tree;
    boost::property_tree::read_xml(filepath, property_tree);
    auto config = property_tree.get_child("Config");
    std::string timestamp_type = config.get<std::string>("ReportingUnits");
    if(!timestamp_type.compare("seconds") || !timestamp_type.compare("s"))
    {
        _timestamp_v = std::chrono::seconds();
    }
    else if(!timestamp_type.compare("milliseconds") || !timestamp_type.compare("ms"))
    {
        _timestamp_v = std::chrono::milliseconds();
    }
    else if(!timestamp_type.compare("microseconds") || !timestamp_type.compare("us"))
    {
        _timestamp_v = std::chrono::microseconds();
    }
    else if(!timestamp_type.compare("nanoseconds") || !timestamp_type.compare("ns"))
    {
        _timestamp_v = std::chrono::nanoseconds();
    }
}

void OutputFunction()
{
   std::cout << std::visit(GetTimestampVisitor, _timestamp_v) << std::endl;
}

我承认我不擅长元编程。有没有更简单的方法来做到这一点?本质上,我只能在编译时保证持续时间的类型将是持续时间类型的子集之一。

boost c++17 metaprogramming c++-chrono
1个回答
0
投票

始终以足够的精度存储普通的

duration
。然后将输出缩放到所需的演示格式:

住在Coliru

#include <boost/property_tree/xml_parser.hpp>
#include <chrono>
#include <iostream>
#include <map>

struct Program {
    using duration = std::chrono::steady_clock::duration;

    auto ReportingDuration(duration d) const {
        using namespace std::chrono_literals;
        using unit = decltype(1.ns); // or `duration` for integral

        static std::map<std::string_view, unit> const units = {
            {"ns", 1ns}, {"nanoseconds", 1ns},  //
            {"us", 1us}, {"microseconds", 1us}, //
            {"ms", 1ms}, {"milliseconds", 1ms}, //
            {"s", 1s},   {"seconds", 1s},       //
            {"m", 1min}, {"minutes", 1min},     //
            {"h", 1h},   {"hours", 1h},         //
            {"d", 24h},  {"days", 24h},
        };
        return d / units.at(reporting_unit_);
    };

    bool ReportingUnitValid() const try {
        return ReportingDuration(std::chrono::hours(24)), true;
    } catch (...) {
        return false;
    }

    void SetupFunction(std::string const& filepath = "config.xml") {
        boost::property_tree::ptree pt;
        read_xml(filepath, pt);
        reporting_unit_ = pt.get<std::string>("Config.ReportingUnits");
        if (!ReportingUnitValid())
            throw std::runtime_error("Invalid reporting unit");
    }

    void OutputFunction() {
        using namespace std::chrono_literals;
        for (duration v : std::vector<duration> //
             {                                  //
              1ns, 1us, 1ms, 1s,                //
              1min,                             //
              1h, 1h + 1min,                    //
              1h + 1min + 1s,                   //
              24h, 24h + 1min, 24h + 1min + 1s})
            std::cout << std::setw(16) << v << ": " << ReportingDuration(v) << " " << reporting_unit_
                      << std::endl;
    }

  private:
    std::string reporting_unit_ = "s";
};

int main() {
    std::cout << std::fixed;
    Program p;
    p.SetupFunction();
    p.OutputFunction();
}

所有测试:

g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp 
for unit in d h m s ms us ns; do cat > config.xml <<< "<Config><ReportingUnits>$unit</ReportingUnits></Config>"; ./a.out; done

印刷:

             1ns: 0 d
          1000ns: 0 d
       1000000ns: 0 d
    1000000000ns: 0 d
   60000000000ns: 0 d
 3600000000000ns: 0 d
 3660000000000ns: 0 d
 3661000000000ns: 0 d
86400000000000ns: 1 d
86460000000000ns: 1 d
86461000000000ns: 1 d
             1ns: 0 h
          1000ns: 0 h
       1000000ns: 0 h
    1000000000ns: 0 h
   60000000000ns: 0 h
 3600000000000ns: 1 h
 3660000000000ns: 1 h
 3661000000000ns: 1 h
86400000000000ns: 24 h
86460000000000ns: 24 h
86461000000000ns: 24 h
             1ns: 0 m
          1000ns: 0 m
       1000000ns: 0 m
    1000000000ns: 0 m
   60000000000ns: 1 m
 3600000000000ns: 60 m
 3660000000000ns: 61 m
 3661000000000ns: 61 m
86400000000000ns: 1440 m
86460000000000ns: 1441 m
86461000000000ns: 1441 m
             1ns: 0 s
          1000ns: 0 s
       1000000ns: 0 s
    1000000000ns: 1 s
   60000000000ns: 60 s
 3600000000000ns: 3600 s
 3660000000000ns: 3660 s
 3661000000000ns: 3661 s
86400000000000ns: 86400 s
86460000000000ns: 86460 s
86461000000000ns: 86461 s
             1ns: 0 ms
          1000ns: 0 ms
       1000000ns: 1 ms
    1000000000ns: 1000 ms
   60000000000ns: 60000 ms
 3600000000000ns: 3600000 ms
 3660000000000ns: 3660000 ms
 3661000000000ns: 3661000 ms
86400000000000ns: 86400000 ms
86460000000000ns: 86460000 ms
86461000000000ns: 86461000 ms
             1ns: 0 us
          1000ns: 1 us
       1000000ns: 1000 us
    1000000000ns: 1000000 us
   60000000000ns: 60000000 us
 3600000000000ns: 3600000000 us
 3660000000000ns: 3660000000 us
 3661000000000ns: 3661000000 us
86400000000000ns: 86400000000 us
86460000000000ns: 86460000000 us
86461000000000ns: 86461000000 us
             1ns: 1 ns
          1000ns: 1000 ns
       1000000ns: 1000000 ns
    1000000000ns: 1000000000 ns
   60000000000ns: 60000000000 ns
 3600000000000ns: 3600000000000 ns
 3660000000000ns: 3660000000000 ns
 3661000000000ns: 3661000000000 ns
86400000000000ns: 86400000000000 ns
86460000000000ns: 86460000000000 ns
86461000000000ns: 86461000000000 ns

现场演示:

© www.soinside.com 2019 - 2024. All rights reserved.