Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.)

like image 747
Frank Avatar asked May 18 '09 19:05

Frank


People also ask

What is a wrapper function in C?

A wrapper function is a subroutine (another word for a function) in a software library or a computer program whose main purpose is to call a second subroutine or a system call with little or no additional computation.

What is a wrapper function example?

A function wrapper encapsulates one or more functions. For example, a website's "send mail" function may wrap multiple functions that process form data, check the submission for spam, and send the message using a mail server.

Are wrapper functions recursive?

The wrapper function itself is not recursive, but the function it calls is! Python only creates default values once ever and reuses those values on each call. If you mutate those values, you will get unexpected results, where it works once properly, and then not after that.

Does C++ have wrapper class?

Wrapper class in C++ Wrapper is generally defined as the packaging, or to bound an object. A "wrapper class" is used to manage the resources so that it will be crystal-clear to every one. This wraps the resources by simply wrapping the pointer into an int. In this another function is called having less code.


1 Answers

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.

like image 119
Johannes Schaub - litb Avatar answered Nov 02 '22 00:11

Johannes Schaub - litb