kfmfe04
kfmfe04

Reputation: 15337

callback vs lambda

Suppose I have the following code that I wish to refactor:

int toFuture()
{
  precalc();
  int calc = 5 * foobar_x() + 3;
  postcalc();
  return calc;
}

int toPast()
{
  precalc();
  int calc = 5 * foobar_y() - 9;
  postcalc();
  return calc;
}

In classic-C, I would refactor this code into a worker() which accepts a function pointer that does the calculation: common code in worker(), specific code provided by function pointer.

With C++11, should I be using a lambda instead? If so, how would I implement it, in this case?

Edit: it just crossed my mind that a template may also work. How would a template implementation compare against the other two?

Upvotes: 28

Views: 6925

Answers (4)

ildjarn
ildjarn

Reputation: 62995

One approach:

template<typename CalcFuncT>
int perform_calc(CalcFuncT&& calcfunc)
{
    precalc();
    int const calc = std::forward<CalcFuncT>(calcfunc)();
    postcalc();
    return calc;
}

int main()
{
    perform_calc([]{ return 5 * foobar_x() + 3; }); // toFuture
    perform_calc([]{ return 5 * foobar_y() - 9; }); // toPast
}

Upvotes: 41

MSalters
MSalters

Reputation: 180235

I'd say you're refactoring from the wrong side:

struct CalcGuard {
  CalcGuard() { /* replaces precalc() */ }
  ~CalcGuard() { /* replaces postcalc() */ }
};

int toFuture()
{
  return CalcGuard(), calc = 5 * foobar_x() + 3;
}

int toPast()
{
  return CalcGuard(), calc = 5 * foobar_y() - 9;
}

Upvotes: 8

Jason
Jason

Reputation: 32538

If you are wanting a template approach using C++11 features, that could look as simple as:

template<typename FuncType>
auto calculation(FuncType&& func) -> decltype(func())
{
    precalc();
    auto ret = func();
    postcalc();
    return ret;
}

You would then simply call your calculation function and pass it either a lambda, a functor, or a function-pointer. Your only souce of difficulty in this instance would be if you passed a function that had a void return-type ... in that case you will get a compiler error (which is a good thing vs. a runtime error).

Upvotes: 22

TonyK
TonyK

Reputation: 17124

There is a C/C++ way to do this, and a C++11 way. Neither way involves lambdas or templates.

The C/C++ way:

double MyFunc (int x, float y) { return x + y ; }

int main()
  {
  double (*pf) (int, float) ;
  pf = MyFunc ;
  pf (101, 202.0) ;
  }

The C++11 way:

#include <functional>

double MyFunc (int x, float y) { return x + y ; }

int main()
  {
  std::function<double (int, float)> f ;
  f = MyFunc ;
  f (51, 52.0) ;
  }

In either case, you just pass pf or f to your refactored function as a parameter. Using lambdas or templates is overkill here.

Upvotes: 1

Related Questions