c++如何将成员函数一般地转换为独立函数(用作函数参数)

C++ how to convert member functions to standalone functions (for use as function parameter) generically?

本文关键字:函数 独立 参数 转换 成员 c++      更新时间:2023-10-16

对于模板函数的函数参数,我发现自己经常将成员函数包装在lambda中以创建相同的独立函数,第一个参数为对象。

(虚拟)示例:

class A
{
public:
    double f1() const;
    double f2(int i) const;
    // some data
};
template <typename Func>
double calculateSum(std::vector<A> as, Func f)
{
    double result = 0.0;
    for (auto a : as)
        result += f(a);
    return result;
}
int main()
{
    std::vector<A> as;
    int i = 0;
    auto sum1 = calculateSum(as, [](const A& a) { return a.f1(); });
    auto sum2 = calculateSum(as, [&i](const A& a) { return a.f2(i); });
    return 0;
}

是否有一种方法来定义这样的lambdas更一般?或者有一种方法可以直接引用成员函数,而不是使用lambda ?

您可以使用c++ 14泛型lambdas来帮助完成此操作。像这样定义你的泛型lambda:

auto bindMem = [](auto f, auto& ... memArgs) { return [f, &memArgs...](auto& a) { return (a.*f)(memArgs...); }; };

要理解:这会创建一个泛型lambda,调用它会产生另一个lambda。第一个lambda获取您想要调用的成员函数,以及任何绑定参数(this对象除外)。它生成第二个lambda,然后该lambda期望对象本身,并使用前面绑定的形参对其应用成员函数调用。

对于你的用例,你有一个整洁的:

auto sum1 = calculateSum(as, bindMem(&A::f1));
auto sum2 = calculateSum(as, bindMem(&A::f2,i));

这样做的好处是,完全相同的bindMem lambda将适用于任何类和任何成员函数,具有任意参数列表。所以它确实是通用的

经过一番研究,感谢@happydave的建议,我将采用以下答案:

auto sum1 = calculateSum(as, std::mem_fn(&A::f1));

第二个和不能这样处理,应该保持为lambda。然而,一般来说,客户机代码是参数提供者的情况似乎不太可能出现(在这种情况下,需要将参数无论如何传递给模板函数(lambda捕获是一种很好的方法))。在许多情况下,模板函数还提供传递的函数的参数,std::mem_fn就可以了。

您可以使用std::bind()

Bind接受一个函数和您想要使用的许多参数,并返回一个不错的std::function对象。您可以在创建时指定参数,也可以在调用返回函数时使用占位符指定参数。

#include <functional>
...
auto sum1 = calculateSum(as, std::bind(&A::f1, std::placeholders::_1));
auto sum2 = calculateSum(as, std::bind(&A::f2, std::placeholders::_1, i);

请记住,非静态成员函数将类实例作为其第一个参数(尽管大多数情况下是隐式的,这不是其中之一),这就是我们使用占位符的原因。当您现在执行f(a)时,a(类实例)将替换占位符。

进一步阅读:Bind, placeholder