回调vs lambda

kfm*_*e04 26 c++ lambda c++11

假设我有以下代码我想重构:

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

int toPast()
{
  precalc();
  int calc = 5 * foobar_y() - 9;
  postcalc();
  return calc;
}
Run Code Online (Sandbox Code Playgroud)

在classic-C中,我将这个代码重构为一个worker(),它接受一个执行计算的函数指针:worker()中的公共代码,函数指针提供的特定代码.

使用C++ 11,我应该使用lambda吗?如果是这样,在这种情况下我将如何实现它?

编辑:我只是想到一个模板也可以工作.模板实现如何与其他两个进行比较?

ild*_*arn 40

一种方法:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 简单的美丽! (4认同)

Jas*_*son 22

如果您想要使用C++ 11功能的模板方法,那可能看起来很简单:

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

然后,您只需调用calculation函数并将其传递给lambda,functor或函数指针.在这种情况下,你唯一的困难就是如果你传递了一个具有void返回类型的函数......在这种情况下,你将得到编译器错误(这对运行时错误是一件好事).

  • @Jason:这是一个选项,但通常一个仿函数不应该拥有它的状态 - 状态应该由外部拥有并由仿函数内部的引用/指针保存.也就是说,因为我们已经在使用C++ 11语法,如果`func`类型为`FuncType &&`,那么两者同时支持相同的代码,因为引用折叠规则会将传入的左值视为`FuncType& `无论如何.我非常喜欢这个,所以我也改变了我的回答.: - ] (2认同)

MSa*_*ers 7

我会说你是从错误的方面重构:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • +1,但主要的缺点是,如果`postcalc`有可能'throw`,那么一个人将被强制放入`~CalcGuard`的异常处理将在错误的地方. (2认同)