1

I am building some library functions, one of which is basically a timer class with an arbitrary key. It looks conceptually like this:

template <typename Key>
class Timer
{
  void tic(Key key) {tics[key] = std::clock();
  void toc(Key key)
  {
    // calling this before tic has been called is fine
    if (!tic.find(key))
      tocs[key] = 0;
    else
      tocs[key] = std::clock() - tics[key];

    // BUT: writing code that calls "tocs" without ever calling "tics" should trigger
    // a compile-time error! How do I do this? Is it possible?
  }
  private:
  std::map<Key,clock_t> tics;
  std::map<Key,clock_t> tocs;
}

The task of this class is just to measure the time between tic and toc calls for each key. It should be perfectly legal to call toc before tic in order to allow the class to measure time between function calls, for example. However, calling a tic or a toc without some corresponding toc/tic in other parts of the code simply makes no sense, so it's obviously a coding error - which I would like to report at compile-time.

So, this should be ok:

Timer<int> timer;

while (1)
{
  timer.toc(0);
  // this reports the time elapses between the while 
  // loop ending and the while loop starting
  timer.tic(1);
}

but these should generate compile-time errors (well, warnings would be more suitable):

Timer<int> timer;

while (1)
{
  timer.toc(1); // this will always return 0
  timer.tic(0); // this is an unused initialization
}

Is it possible to achieve this? I suspect the answer is no but I wanted to make sure, because it would be really neat.

4

1 回答 1

0

As you liked the proposition in comments, here is an example:

template<typename Key>
class Timer
{
 class CachePair
 {
  clock_t lastTimestamp, diff;

 public:
  CachePair() :
   lastTimestamp(0), diff(0)
  { }

  void update()
  {
   clock_t now = std::clock();
   diff = now - lastTimestamp;
   lastTimestamp = now;
  }
 };

 std::map<Key, CachePair> cache;

public:
 Timer()
 { }

 void tick(Key const& key)
 {
  cache[key].update();
 }

 clock_t const& value(Key const& key)
 {
  return cache[key].diff;
 }
};

Did not test it. This could be improved if you are using C++11 to avoid initialization in CachePair constructor when you are calling update(Key) for the first time on a Key.

Actually you can even eliminate the second variable if size matters that much and also eliminate much of the complication.

template<typename Key>
class Timer
{    
 std::map<Key, clock_t> cache;

public:
 Timer()
 { }

 clock_t tick(Key const& key)
 {
  clock_t& val = cache[key];

  clock_t now = std::clock();
  val = now; //this will update the value in map because it is defined as a reference to the variable in map
  return now - val;
 }
};

Way simpler huh, naturally better because has easier interface / less methods. You just need to type size_t timeElapsed = timer.tick(key); to get the time elapsed between two ticks.

于 2013-11-10T03:22:26.303 回答