如何使用 lambdas 将 std::function 与成员函数一起使用?
How to use lambdas to use std::function with member functions?
我正在尝试将一些全局函数移动到 class 中。当前代码如下所示:
struct S{};
void f(S* s, int x, double d){}
void g(S* s, int x, double d){}
/*
...
...*/
void z(S* s, int x, double d){}
int main()
{
function<void(S*, int, double)> fp;
//switch(something)
//case 1:
fp = f;
//case 2:
fp = g;
//case n:
fp = z;
}
假设我想将上面的代码更新为类似(下面的代码无法编译):
#include <iostream>
#include <functional>
using namespace std;
struct S
{
void f(int x, double d){}
void g(int x, double d){}
/*
...
...*/
void z(int x, double d){}
void method_that_has_some_logic_to_use_the_others_above(int x, double d)
{
function<void(int, double)> fp; // How do I have to declare here?
//switch(something)
//case 1:
fp = f; // How can achieve something like this using lambdas here?
//case 2:
fp = g;
//case n:
fp = z;
fp(x, d);
}
};
int main()
{
S s;
s.method_that_has_some_logic_to_use_the_others_above(10, 5.0);
}
我见过一些使用 std::bind 的解决方案,但在某处阅读以避免使用它并更喜欢 lambda。我使用的是 C++17,但我对 lambda 没有什么经验,无法用我在其他答案中找到的示例弄清楚如何解决它。
成员函数需要一个特定的class对象来调用,所以你需要做
function<void(S*, int, double)> fp = &S::f;
fp(this, x, d);
或者使用lambda捕获特定的class对象并在内部调用其成员函数
function<void(int, double)> fp = [this](int x, double d) { this->f(x, d); };
fp(x, d);
注意: 我提出了另一种方法,因为 OP 无法证明使用 std::function
的合理性(并且因为对字面问题已经被康桐蔚给过了)。
只要您只是在要调用的具有相同签名 的成员函数之间进行选择,std::function
就会产生不必要的开销。开销可能并不重要,如果您需要扩展到简单的成员函数调用之外,您确实有更多的灵活性。另一方面,pointer-to-member-function 提供类似的功能而没有开销。
缺点(对我来说)是语法。本例中的类型是 void (S::*)(int, double)
,如果您不习惯 pointers-to-member,则很难阅读。最重要的是,声明的变量位于类型的中间,这再次损害了可读性。不过,如果您可以接受语法:
// Placeholder for the decision-making process:
char choose_fun() { return 'g'; }
// Same setup for `S` as in the question, except with the following added:
void S::other_method(int x, double d)
{
void (S::* fp)(int, double); // Manual type specification
// decltype(&S::other_method) fp; // Possibly easier to read
switch (choose_fun()) {
case 'f': fp = &S::f; break;
case 'g': fp = &S::g; break;
// ...
}
// More processing?
// The syntax for invoking a pointer-to-member is also a bit weird.
(this->*fp)(x, d);
}
实际上,如果设置真的像问题中提出的那样简单(一个简单的 switch
来决定调用什么),我可能不会在指针或 std::function
中费心这个设置。我会存储 switch
使用的值,然后通过辅助函数调用这些函数。 (如果没有额外处理,那么other_method
就简化为helper函数。)
// The helper function.
void S::choose_method(char choice, int x, double d)
{
switch (choice) {
// Returning void is legal and takes the place of having a `break`.
case 'f': return f(x, d);
case 'g': return g(x, d);
// ...
}
}
// Now the other method needs very little code in addition to the additional
// processing, whatever that is. This also brings the code closer to the
// ideal of one task per function.
void S::other_method(int x, double d)
{
char choice = choose_fun();
// More processing
choose_method(choice, x, d);
}
我正在尝试将一些全局函数移动到 class 中。当前代码如下所示:
struct S{};
void f(S* s, int x, double d){}
void g(S* s, int x, double d){}
/*
...
...*/
void z(S* s, int x, double d){}
int main()
{
function<void(S*, int, double)> fp;
//switch(something)
//case 1:
fp = f;
//case 2:
fp = g;
//case n:
fp = z;
}
假设我想将上面的代码更新为类似(下面的代码无法编译):
#include <iostream>
#include <functional>
using namespace std;
struct S
{
void f(int x, double d){}
void g(int x, double d){}
/*
...
...*/
void z(int x, double d){}
void method_that_has_some_logic_to_use_the_others_above(int x, double d)
{
function<void(int, double)> fp; // How do I have to declare here?
//switch(something)
//case 1:
fp = f; // How can achieve something like this using lambdas here?
//case 2:
fp = g;
//case n:
fp = z;
fp(x, d);
}
};
int main()
{
S s;
s.method_that_has_some_logic_to_use_the_others_above(10, 5.0);
}
我见过一些使用 std::bind 的解决方案,但在某处阅读以避免使用它并更喜欢 lambda。我使用的是 C++17,但我对 lambda 没有什么经验,无法用我在其他答案中找到的示例弄清楚如何解决它。
成员函数需要一个特定的class对象来调用,所以你需要做
function<void(S*, int, double)> fp = &S::f;
fp(this, x, d);
或者使用lambda捕获特定的class对象并在内部调用其成员函数
function<void(int, double)> fp = [this](int x, double d) { this->f(x, d); };
fp(x, d);
注意: 我提出了另一种方法,因为 OP 无法证明使用 std::function
的合理性(并且因为对字面问题已经被康桐蔚给过了)。
只要您只是在要调用的具有相同签名 的成员函数之间进行选择,std::function
就会产生不必要的开销。开销可能并不重要,如果您需要扩展到简单的成员函数调用之外,您确实有更多的灵活性。另一方面,pointer-to-member-function 提供类似的功能而没有开销。
缺点(对我来说)是语法。本例中的类型是 void (S::*)(int, double)
,如果您不习惯 pointers-to-member,则很难阅读。最重要的是,声明的变量位于类型的中间,这再次损害了可读性。不过,如果您可以接受语法:
// Placeholder for the decision-making process:
char choose_fun() { return 'g'; }
// Same setup for `S` as in the question, except with the following added:
void S::other_method(int x, double d)
{
void (S::* fp)(int, double); // Manual type specification
// decltype(&S::other_method) fp; // Possibly easier to read
switch (choose_fun()) {
case 'f': fp = &S::f; break;
case 'g': fp = &S::g; break;
// ...
}
// More processing?
// The syntax for invoking a pointer-to-member is also a bit weird.
(this->*fp)(x, d);
}
实际上,如果设置真的像问题中提出的那样简单(一个简单的 switch
来决定调用什么),我可能不会在指针或 std::function
中费心这个设置。我会存储 switch
使用的值,然后通过辅助函数调用这些函数。 (如果没有额外处理,那么other_method
就简化为helper函数。)
// The helper function.
void S::choose_method(char choice, int x, double d)
{
switch (choice) {
// Returning void is legal and takes the place of having a `break`.
case 'f': return f(x, d);
case 'g': return g(x, d);
// ...
}
}
// Now the other method needs very little code in addition to the additional
// processing, whatever that is. This also brings the code closer to the
// ideal of one task per function.
void S::other_method(int x, double d)
{
char choice = choose_fun();
// More processing
choose_method(choice, x, d);
}