代码之家  ›  专栏  ›  技术社区  ›  Mikhail T.

如何将对象的方法传递给lambda函数?

  •  0
  • Mikhail T.  · 技术社区  · 1 年前

    一个复杂的“计算器”当前被调用如下:

                result = calculator.calc(a, b, extra);
    

    不幸的是,它有时可能会因服务器上发生的无关更改而失败。与不同部门同步很困难,重试更容易。。。

    为此,我实施了 retry lambda函数:

        auto retry = [](const auto& func, auto... args) {
            int attempts = 5;
            for (;;) try {
                return func(args...);
            }
            catch (const std::system_error& e) {
                /* Don't retry in case of a system_error */
                throw;
            }
            catch (const exception& e) {
                if (attempts-- == 0)
                    throw; /* Give up and rethrow */
                Logging::log(Logging::Level::Warning,
                    "%s. Retrying %d more times.", e.what(), attempts);
                sleep(2);
            }
        };
    

    上面的代码可以编译,但是,当我尝试使用它时:

                result = retry(calculator.calc, a, b, extra);
    

    我从clang中得到一个错误: reference to non-static member function must be called GNU c++将同一行标记为 invalid use of non-static member function .

    事实上 calc() 是Calculator类的非静态方法。

    我该如何使用我的新lambda?

    2 回复  |  直到 1 年前
        1
  •  2
  •   user17732522    1 年前

    在lambda替换 func(args...) 具有 std::invoke(func, args...) 。现在,除了函数指针/引用、lambda和其他函数对象外,您的lambda还支持可调用的成员函数指针。

    要传递成员函数指针,语法为

    result = retry(&Calculator::calc, &calculator, a, b, extra);
    

    哪里 Calculator 是类类型 calculator .额外的论点 &calculator 在类的指定对象/实例上调用非静态成员函数是必要的。 std::invoke 知道如何自动处理它。

    你在这里需要小心一点。因为你的参数是按值计算的,如果你写 计算器 而不是 &计算器 您将意外调用 复制 属于 计算器 .


    一般来说,最好通过转发引用来传递参数:

    auto retry = [](auto&& func, auto&&... args) {
    

    那么你也可以称之为

    result = retry(&Calculator::calc, calculator, a, b, extra);
    

    std::invoke 知道在调用成员函数指针时处理指针和对类实例的引用。

    但是请注意,因为您可能会调用 func 多次,你不应该 std::forward 转发引用到呼叫中。


    另外,作为旁注,如果你想保留 retry 通用,不足以捕捉 std::exception 。没有要求例外情况必须从以下来源得出 std::异常 。这只是标准库中使用的约定,有时也被其他库使用。

    倒退 catch 所有其他异常的块应该如下所示:

    catch(...)
    {
        // do something
    }
    
        2
  •  2
  •   Jarod42    1 年前

    你可以直接传递一个lambda:

    retry([&](){ return calculator.calc(a, b, extra); });