C++: Function wrapper that behaves just like the function itself

Frank picture Frank · May 18, 2009 · Viewed 22.7k times · Source

How can I write a wrapper that can wrap any function and can be called just like the function itself?

The reason I need this: I want a Timer object that can wrap a function and behave just like the function itself, plus it logs the accumulated time of all its calls.

The scenario would look like this:

// a function whose runtime should be logged
double foo(int x) {
  // do something that takes some time ...
}

Timer timed_foo(&foo); // timed_foo is a wrapping fct obj
double a = timed_foo(3);
double b = timed_foo(2);
double c = timed_foo(5);
std::cout << "Elapsed: " << timed_foo.GetElapsedTime();

How can I write this Timer class?

I am trying something like this:

#include <tr1/functional>
using std::tr1::function;

template<class Function>
class Timer {

public:

  Timer(Function& fct)
  : fct_(fct) {}

  ??? operator()(???){
    // call the fct_,   
    // measure runtime and add to elapsed_time_
  }

  long GetElapsedTime() { return elapsed_time_; }

private:
  Function& fct_;
  long elapsed_time_;
};

int main(int argc, char** argv){
    typedef function<double(int)> MyFct;
    MyFct fct = &foo;
    Timer<MyFct> timed_foo(fct);
    double a = timed_foo(3);
    double b = timed_foo(2);
    double c = timed_foo(5);
    std::cout << "Elapsed: " << timed_foo.GetElapsedTime();
}

(BTW, I know of gprof and other tools for profiling runtime, but having such a Timer object to log the runtime of a few selected functions is more convenient for my purposes.)

Answer

Johannes Schaub - litb picture Johannes Schaub - litb · May 18, 2009

Basically, what you want to do is impossible in current C++. For any number of arity of function you want to wrap, you need to overload by

const reference
non-const reference

But then it's still not perfectly forwarding (some edge cases still stand), but it should work reasonable well. If you limit yourself to const references, you can go with this one (not tested):

template<class Function>
class Timer {
    typedef typename boost::function_types
       ::result_type<Function>::type return_type;

public:

  Timer(Function fct)
  : fct_(fct) {}

// macro generating one overload
#define FN(Z, N, D) \
  BOOST_PP_EXPR_IF(N, template<BOOST_PP_ENUM_PARAMS(N, typename T)>) \
  return_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N, T, const& t)) { \
      /* some stuff here */ \
      fct_(ENUM_PARAMS(N, t)); \
  }

// generate overloads for up to 10 parameters
BOOST_PP_REPEAT(10, FN, ~)
#undef FN

  long GetElapsedTime() { return elapsed_time_; }

private:
  // void() -> void(*)()
  typename boost::decay<Function>::type fct_;
  long elapsed_time_;
};

Note that for the return type, you can use boost's function types library. Then

Timer<void(int)> t(&foo);
t(10);

You can also overload using pure value parameters, and then if you want to pass something by reference, use boost::ref. That's actually a pretty common technique, especially when such parameters are going to be saved (this technique is also used for boost::bind):

// if you want to have reference parameters:
void bar(int &i) { i = 10; }

Timer<void(int&)> f(&bar);
int a; 
f(boost::ref(a)); 
assert(a == 10);

Or you can go and add those overloads for both const and non-const versions as explained above. Look into Boost.Preprocessor for how to write the proper macros.

You should be aware that the whole thing will become more difficult if you want to be able to pass arbitrary callables (not only functions), since you will need a way then to get their result type (that's not all that easy). C++1x will make this sort of stuff way easier.