I had a simple stopwatch class that was basically using std::chrono::steady_clock::now() - this->start_
in its implementation for measuring elapsed time. I have decided to upgrade it and make fully generic, std-compliant, not depending on a particular clock type, so user can specify his own clock type. I also had a template stopwatch::operator DurationType() const
for convenience, to convert to a specific duration type, for instance:
std::chrono::milliseconds msecs = stopwatch;
But there is one problem: I can't get rid of a chrono
header since I am using its duration_cast
.
I have come up with 2 ideas. One of them works but not very convenient, and the other does not work at all and is pretty ugly.
// 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;
}
Whilst the first option works despite its inconvenience, I want to know if I can get rid of std::chrono::duration_cast
in my header in a more elegant way. Or is this as good as it gets?
P.S.: What's wrong with my second approach? Why can't I compile it?
Aucun commentaire:
Enregistrer un commentaire