Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class that stores a std::chrono::duration as a member?

Tags:

c++

c++11

chrono

I want to create a class who's construct takes a std::chrono::duration argument and stores the result in a member so that I can later pass it into std::this_thread::sleep_for().

I know I can write some function template that works like sleep_for as follows:

template <typename Rep, typename Period>
void mySleep( std::chrono::duration<Rep, Period> time )
{
  std::this_thread::sleep_for(time);
}

And this could be a member function of a class. But what about the following case?

class UsesDuration
{
public:
   template <typename Rep, typename Period>
   UsesDuration( std::chrono::duration<Rep, Period> dur ) :
      my_duration(dur) { }

   void doSomethingPeriodic()
   {
       while( some_condition )
       {
          std::this_thread::sleep_for(my_duration);
          somethingInteresting();
       }
   }    

private:
   ???  my_duration;   /* How do I declare this??? */
}

Is there a clean way to keep the duration "abstract" A) ideally w/o turning the entire class into a templated class, B) by turning the class into a class template?

like image 415
Brian McFarland Avatar asked Jan 21 '16 16:01

Brian McFarland


People also ask

What is std :: Chrono :: duration?

Class template std::chrono::duration represents a time interval. It consists of a count of ticks of type Rep and a tick period, where the tick period is a compile-time rational fraction representing the time in seconds from one tick to the next. The only data stored in a duration is a tick count of type Rep .

What is std :: Chrono :: seconds?

std::chrono::secondsInstantiation of duration to represent seconds.


2 Answers

A simpler solution is to just use a std::chrono::duration that is as fine or finer than you'll ever want:

#include <chrono>
#include <thread>

class UsesDuration
{
public:
   UsesDuration( std::chrono::nanoseconds dur ) :
      my_duration(dur) { }

   void doSomethingPeriodic()
   {
       while( some_condition )
       {
          std::this_thread::sleep_for(my_duration);
          somethingInteresting();
       }
   }

   void somethingInteresting();

private:
   std::chrono::nanoseconds  my_duration;
};

int
main()
{
    using namespace std::chrono_literals;
    UsesDuration x{5min};
}

There is no need to template everything, unless you actually want that generality. All of your predefined units implicitly convert to nanoseconds. If you ever get into a state where the client is sending something that won't exactly convert to nanoseconds, you will find out at compile-time, and then you can decide if you want to template, or perhaps go with another solution.

Another solution, which is better than storing a double, is to store a double-based duration:

#include <chrono>
#include <thread>

class UsesDuration
{
public:
   UsesDuration( std::chrono::duration<double> dur ) :
      my_duration(dur) { }

   void doSomethingPeriodic()
   {
       while( some_condition )
       {
          std::this_thread::sleep_for(my_duration);
          somethingInteresting();
       }
   }

   void somethingInteresting();

private:
   std::chrono::duration<double>  my_duration;
};

int
main()
{
    using namespace std::chrono_literals;
    UsesDuration x{5min};
}

Every chrono::duration will implicitly convert to a floating-point duration. In this example I've chosen seconds as the precision, and double as the representation. You could choose anything you want (long double and microseconds, whatever).

You have a lot of options here. And all of them give you type safety that a bare double won't, and without sacrificing performance nor flexibility.

Just use double to store seconds

is the worst advice you can get. Learn <chrono>. It has a lot of flexibility, and there is a great deal of it that doesn't demand templates.


It was perhaps impolite of me to insist that you learn <chrono> without giving you some pointers.

Nicolai M. Josuttis' "The C++ Standard Library - A Tutorial and Reference, 2nd Edition" has an excellent introduction to <chrono>. This chapter alone will pay for the cost of the book. Be sure you get the 2nd edition. His first edition covered C++03, which did not have <chrono>. Disclosure: I have no arrangement (financial or otherwise) to promote Nico's book, though he is a friend of mine.

For those willing to dig into committee papers, the <chrono> proposal is here:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2661.htm

The section on duration (linked in the contents) is where I suggest you start if you are impatient. It reads more like a tutorial than a technical paper as I was attempting to bring the committee itself up to speed. It includes the very advice I have given in my answer above, and more.

And here is a video introductory tutorial:

https://www.youtube.com/watch?v=P32hvk8b13M

like image 122
Howard Hinnant Avatar answered Oct 11 '22 00:10

Howard Hinnant


One solution I can see for this is to just use a particular duration in you class and then you can use std::chrono::duration_cast to cast from the type supplied to the constructor to the type you use as the class member. This allows you to not template the class but still take in any type of duration

template <typename Rep, typename Period>
   UsesDuration( std::chrono::duration<Rep, Period> dur ) :
      my_duration(std::chrono::duration_cast<decltype(my_duration)>(dur)) { }
like image 29
NathanOliver Avatar answered Oct 10 '22 23:10

NathanOliver