如何将 class 方法作为参数传递给另一个函数,然后调用它,最好使变量 class 方法签名显式?

How can I pass a class method as a parameter to another function and later call it, preferably making the variable class method signature explicit?

如果我有一个 class 需要使用 class 方法作为参数调用父 class 方法,我可以使用 std::function + std::bind如下图:

class A {
    void complexMethod(std::function<void()> variableMethod) {
        // other stuff ...
        variableMethod();
        // some other stuff..
    }
}

class B : public A {
    void myWay() {
        // this and that
    }

    void otherWay() {
        // other and different
    }

    void doingSomething() {
        // Preparing to do something complex.
        complexMethod(std::bind(&B::myWay, this));
    }

    void doingAnotherThing() {
        // Different preparation to do some other complex thing.
        complexMethod(std::bind(&B::otherWay, this));
    }
}

我需要如何更改上述代码才能使用模板而不是 std::function + std::bind 来实现相同的功能?

用 lambda 代替 std::function + std::bind 怎么样?我仍然想调用 B:myWay()B::otherWay() 但使用 lambda。我不想用 lambda 替换 B:myWay()B::otherWay()

是否有任何实现技术(上述之一或其他一些)可以使 variableMethod return 类型和参数显式化?我该怎么做?假设 variableMethod 的签名是:

    bool variableMethod(int a, double b);

推荐哪种技术?为什么(速度、灵活性、易用性...)?

模板+lambda解决方案:

struct A
{
    template <typename F>
    void runA(F func)
    {
        cout << 1 << endl;
        func();
        cout << 3 << endl;
    }
};

struct B : A
{
    int number = 2;

    void runnable() { cout << number << endl; }

    void runB()
    {
        cout << 0 << endl;
        runA([this]() { runnable(); });
        cout << 4 << endl;
    }
};

int main()
{
    B variable;
    variable.runB();
}

为了将函数作为模板参数,只需像上面那样接收该函数的模板类型即可。 lambdas 可以用来代替 bind 使事情变得更容易(this 被传递到 lambda 捕获列表)。

明确声明参数:

void run_func(std::function<bool(int, double)> func)
{
    bool b = func(10, 10.01);
}

std::function 允许您像上面那样定义论点和 return 类型。

How would I need to change the above code to implement the same thing using templates instead of std::function + std::bind?

And how about lambdas instead of std::function + std::bind? I still want to call B:myWay() and B::otherWay() but using lambdas. I don't want to substitute B:myWay() and B::otherWay() with lambdas.

你可以使用 lambda,是的。

类似 [this]() { return myWay(); } 的东西:

  • 捕获 this,并且
  • 调用当前object的一个方法。

[Demo]

#include <iostream>  // cout

class A {
protected:
    template <typename F>
    void complexMethod(F&& f) { f(); }
};

class B : public A {
    void myWay() { std::cout << "myWay\n"; }
    void otherWay()  { std::cout << "otherWay\n"; }
public:
    void doingSomething() {
        complexMethod([this]() { return myWay(); });
    }
    void doingAnotherThing() {
        complexMethod([this]() { return otherWay(); });
    }
};

int main() {
    B b{};
    b.doingSomething();
    b.doingAnotherThing();
}

// Outputs:
//
//   myWay
//   otherWay

Is there any implementation technique (one of the above or some other) were I would be able to make variableMethod return type and parameters explicit? How would I do it?

您可以使用 const std::function<bool(int,double)>& f 作为接收 complexMethod 函数的参数。并且仍然传递一个 lambda。请注意,尽管 lambda 表达式现在正在接收 (int i, double d)(也可能是 (auto i, auto d))。

[Demo]

#include <functional>  // function
#include <ios>  // boolalpha
#include <iostream>  // cout

class A {
protected:
    bool complexMethod(const std::function<bool(int,double)>& f, int i, double d)
    { return f(i, d); }
};

class B : public A {
    bool myWay(int a, double b) { return a < static_cast<int>(b); }
    bool otherWay(int a, double b)  { return a*a < static_cast<int>(b); }
public:
    bool doingSomething(int a, double b) {
        return complexMethod([this](int i, double d) {
            return myWay(i, d); }, a, b);
    }
    bool doingAnotherThing(int a, double b) {
        return complexMethod([this](auto i, auto d) {
            return otherWay(i, d); }, a, b);
    }
};

int main() {
    B b{};
    std::cout << std::boolalpha << b.doingSomething(3, 5.5) << "\n";
    std::cout << std::boolalpha << b.doingAnotherThing(3, 5.5) << "\n";
}

// Outputs:
//
//   true
//   false

请注意,同样可以使用模板完成,尽管您不会使签名显式。

[Demo]

#include <functional>  // function
#include <ios>  // boolalpha
#include <iostream>  // cout

class A {
protected:
    template <typename F, typename... Args>
    auto complexMethod(F&& f, Args&&... args) -> decltype(f(args...))
    { return f(args...); }
};

class B : public A {
    bool myWay(int a, double b) { return a < static_cast<int>(b); }
    bool otherWay(int a, double b)  { return a*a < static_cast<int>(b); }
public:
    bool doingSomething(int a, double b) {
        return complexMethod([this](auto i, auto d) {
            return myWay(i, d); }, a, b);
    }
    bool doingAnotherThing(int a, double b) {
        return complexMethod([this](auto i, auto d) {
            return otherWay(i, d); }, a, b);
    }
};

int main() {
    B b{};
    std::cout << std::boolalpha << b.doingSomething(3, 5.5) << "\n";
    std::cout << std::boolalpha << b.doingAnotherThing(3, 5.5) << "\n";
}

// Outputs:
//
//   true
//   false

Which technique is recommended? Why (speed, flexibility, readility...)?

Scott Meyer 的 Effective Modern C++ 一书的第 34 项标题为 Prefer lambdas to std::bind。它以一句话总结结束:Lambdas are more readable, more expressive, and may be more efficient than using std::bind。但是,它也提到了 std::bind 可能比 lambda 有用的情况。