如何将函数作为参数传递

How to pass a function as parameter

本文关键字:参数传递 函数      更新时间:2023-10-16

我有两个基本相同的方法,所以我正在考虑重构它们。

一个简单的版本是:

void C::GetEmailAlerts(set<AlertPtr>& alertSet)
{
  ...
  ... 
  AlertPtr pAlert = Cache::Get()->GetAlert();
  for (...) {
    ...
    if (pAlert->isEmail())
      alertSet.insert(p);
  }
  ...
}
void C::GetMobileAlerts(set<AlertPtr>& alertSet)
{
  ...
  ... 
  AlertPtr pAlert = Cache::Get()->GetAlert();
  for (...) {
    ...
    if (pAlert->isMobile())
      alertSet.insert(p);
  }
  ...
}

有可能把它做成这样吗:

void C::GetAlerts(set<AlertPtr>& alertSet, ??? func) // How to pass a function as parameter?
{
  ...
  ... 
  AlertPtr pAlert = Cache::Get()->GetAlert();
  for (...) {
    ...
    if (pAlert->func())
      alertSet.insert(p);
  }
  ...
}

所以我只需要打电话:

C c;
c.GetAlerts(emailSet, isEmail);
c.GetAlerts(mobileSet, isMobile);

------------------------编辑------------------------

也许一个通用的例子更容易演示我想要的东西:

#include <iostream>
using namespace std;
struct A
{
    int foo() { cout<<"in foo()"<<endl; }
    int bar() { cout<<"in bar()"<<endl; }
};
A *instance = new A();
struct C
{
public:
  void test1()
  {
    instance->foo();
  }
  void test2()
  {
    instance->bar();
  }
//  void test(???) // How to pass member function as a pointer?
//  {
//    instance->f();
//  }
};
int main()
{
  C c;
  c.test1();
  c.test2();
//  c.test(&A::foo);
//  c.test(&A::bar);
  return 0;
}

在第二个例子中,我想用c.test(&A::foo);来代替c.test1(),可能还有c.test2、c.test3…

有干净的方法吗?

好吧,取决于情况。如果使用的是C++11,则可以使用auto类型,然后执行参数。否则,您需要知道该函数是否为intvoidchar等,然后执行给定的参数。

如果isEmail像这样:bool AlertPtr::isEmail(),您应该使用以下代码:

void C::GetAlerts(set<AlertPtr>& alertSet, bool (AlertPtr::*func)())
{
    ...
    ... 
    AlertPtr pAlert = Cache::Get()->GetAlert();
    for (...) {
        ...
        if (pAlert->func)
            alertSet.insert(p);
    }
    ...
}

为什么不在同一函数中级联if (pAlert->isMobile())if (pAlert->isEmail())

使用函数指针来处理这个问题似乎过于复杂。

void C::GetAlerts(set<AlertPtr>& emailAlertSet, set<AlertPtr>& mobileAlertSet)
{
  ...
  ... 
  AlertPtr pAlert = Cache::Get()->GetAlert();
  for (...) {
    ...
    if (pAlert->isEmail()) {
      emailAlertSet.insert(p);
    else if (pAlert->isMobile()) {
      mobileAlertSet.insert(p);
    }
  }
  ...
}

非常简单,只需使用名称空间即可在名称空间中定义每个名称空间,并可以使用勺运算符轻松访问它们

对于可能感兴趣的人,我终于想出了如何做到这一点:

void C::GetAlerts(set<AlertPtr>& alertSet, bool (AlertClass::func)())
{
  ...
  if ((pAlert->*func)())
    ...
}

这就是我们对这个函数的称呼:

C c;
c.GetAlerts(emailSet, &AlertClass::isEmail);
c.GetAlerts(mobileSet, &AlertClass::isMobile);

第二个例子的完整解决方案:

#include <functional>
#include <iostream>
using namespace std;
struct A
{
    int foo() { cout<<"in foo()"<<endl; }
    int bar() { cout<<"in bar()"<<endl; }
};
A *instance = new A();
struct C
{
public:
  void testFoo()
  {
    instance->foo();
  }
  void testBar()
  {
    instance->bar();
  }
  void test(int (A::*p)())
  {
    (instance->*p)();
  }
};
int main()
{
  C c;
  c.testFoo();
  c.testBar();
  c.test(&A::foo);
  c.test(&A::bar);
  return 0;
}