首页 > 解决方案 > 通用类标准时间独立模板秒表

问题描述

我有一个简单的秒表类,它基本上std::chrono::steady_clock::now() - this->start_在其实现中用于测量经过的时间。我决定升级它并使其完全通用,符合标准,不依赖于特定的时钟类型,因此用户可以指定自己的时钟类型。为了方便起见,我还有一个模板stopwatch::operator DurationType() const,可以转换为特定的持续时间类型,例如:

std::chrono::milliseconds msecs = stopwatch;

但是有一个问题:我无法摆脱一个chrono标题,因为我正在使用它的duration_cast.

我想出了2个想法。其中一个可以工作,但不是很方便,另一个根本不工作,而且很丑。

// stopwatch.h
#pragma once

// #include <chrono>

namespace eld
{
    template <typename ClockType,
            typename DurationCaster>
    class stopwatch
    {
    public:

        using clock_type = ClockType;
        using duration = typename clock_type::duration;

        stopwatch()
             : start_(clock_type::now())
        {}

        void reset()
        {
            start_ = clock_type::now();
        }

        typename clock_type::duration result() const
        {
            return clock_type::now() - start_;
        }

        template<typename Duration>
        Duration result() const
        {
            // return std::chrono::duration_cast<Duration>(result()); // TODO: remove this
            return DurationCaster()(Duration(), result());
        }

        template<typename Duration>
        operator Duration() const
        {
            return result<Duration>();
        }

        // This is ugly and does not work
//        template <typename Caster>
//        auto operator()(Caster caster) -> decltype(Caster::operator()(typename clock_type::time_point))
//        {
//            return caster(result());
//        }

    private:
        typename clock_type::time_point start_;
    };

}

// dummy.cpp

#include <stopwatch/stopwatch.h>

#include <iostream>
#include <chrono>
#include <thread>

// this is inconvenient
struct DurationCaster
{
    template<typename ToDuration, typename FromDuration>
    constexpr ToDuration operator()(ToDuration, FromDuration fromDuration) const
    {
        return std::chrono::duration_cast<ToDuration>(fromDuration);
    }
};

int main()
{

    eld::stopwatch<std::chrono::steady_clock, DurationCaster> steadyWatch{};

    std::this_thread::sleep_for(std::chrono::milliseconds(20));

    std::chrono::nanoseconds nanoseconds = steadyWatch.result();
    std::cout << nanoseconds.count() << std::endl;

    std::chrono::milliseconds milliseconds = steadyWatch;
    std::cout << milliseconds.count() << std::endl;

    // This is ugly and does not work
//    milliseconds = steadyWatch([](typename decltype(steadyWatch)::duration from)
//            {
//        return std::chrono::duration_cast<std::chrono::milliseconds>(from);
//            });

    return 0;
}

std::chrono::duration_cast尽管第一个选项虽然不便,但仍然有效,但我想知道是否可以以更优雅的方式摆脱标题。或者这是最好的吗?

PS:我的第二种方法有什么问题?为什么我编译不出来?

标签: c++c++11templatesgeneric-programming

解决方案


如果您想使用第一种方法,也许将 DurationCaster 作为参数传递给构造函数,那么可以使用函数而不仅仅是函数对象?而且你不需要DurationCaster每次都创建operator(),只做一次。
或者,您可以使用 default DurationCaster,它duration_cast在引擎盖下使用,定义如下typename DurationCaster = your_default_caster

关于为什么不工作的第二个:正如我所见,这里有一个错误decltype(Caster::operator()(typename clock_type::time_point)),您将其operator称为静态成员函数,这是错误的。

这应该有效:

template <typename Caster>
auto operator()(Caster caster) -> typename std::result_of<Caster(typename clock_type::duration)>::type
{
    return caster(result());
}

PS:我知道result_of已弃用,但问题是关于 cpp11


推荐阅读