English 中文(简体)
我如何将类成员函数作为回调函数传递?
原标题:
  • 时间:2008-12-30 13:35:35
  •  标签:

我正在使用一个API,需要我传递一个函数指针作为回调。我试图从我的类中使用这个API,但是我遇到了编译错误。

这是我从构造函数中所做的:

m_cRedundencyManager->Init(this->RedundencyManagerCallBack);

这个不能编译 - 我会得到以下错误:

错误8 错误C3867:CLoggersInfra::RedundencyManagerCallBack:函数调用缺少参数列表;使用 &CLoggersInfra::RedundencyManagerCallBack 创建成员指针。

我尝试了使用&CLoggersInfra::RedundencyManagerCallBack的建议 - 对我没用。

有什么建议或解释吗?

我正在使用VS2008。

谢谢!! (Xièxiè!!)

最佳回答

这不起作用,因为成员函数指针无法像普通函数指针一样处理,因为它需要一个“this”对象参数。

你可以像普通的非成员函数一样传递一个静态成员函数,具体请参考以下方法:

m_cRedundencyManager->Init(&CLoggersInfra::Callback, this);

该函数可以定义如下:

static void Callback(int other_arg, void * this_pointer) {
    CLoggersInfra * self = static_cast<CLoggersInfra*>(this_pointer);
    self->RedundencyManagerCallBack(other_arg);
}
问题回答

这是一个简单的问题,但答案却令人惊讶地复杂。简短的答案是您可以使用std::bind1stboost::bind来做您想做的事情。更详细的答案如下。

编译器建议您使用&CLoggersInfra :: RedundencyManagerCallBack 是正确的。 首先,如果 RedundencyManagerCallBack 是成员函数,则函数本身不属于任何特定的 CLoggersInfra 类实例。 它属于类本身。如果您以前调用过静态类函数,则可以注意到使用相同的 SomeClass :: SomeMemberFunction 语法。由于该函数本身在静态类函数的意义上是属于类而不是特定实例的,因此使用相同的语法。这个'&'是必需的,因为严格来说,您不会直接传递函数--在C ++中,函数不是真正的对象。相反,您在技术上传递函数的内存地址,也就是指向函数在内存中开始的指针。结果是相同的,您实际上正在将一个函数作为参数传递。

但在这种情况下,问题只有一半。正如我所说, RedundencyManagerCallBack 函数并不属于任何特定实例。但听起来您希望将其作为回调传递,并考虑特定实例。要了解如何做到这一点,您需要了解成员函数实际上是什么:具有额外隐藏参数的常规未在任何类中定义的函数。

例如:

class A {
public:
    A() : data(0) {}
    void foo(int addToData) { this->data += addToData; }

    int data;
};

...

A an_a_object;
an_a_object.foo(5);
A::foo(&an_a_object, 5); // This is the same as the line above!
std::cout << an_a_object.data; // Prints 10!

A::foo需要多少个参数?通常我们会说是1个。但实际上,在底层,foo需要2个参数。从A::foo的定义来看,为了使指针this具有意义(编译器需要知道this是什么),它需要A的特定实例。通常,你可以通过语法MyObject.MyMemberFunction()来指定你想要这个this是什么。但这只是一种语法糖,它实际上是将MyObject的地址作为第一个参数传递给MyMemberFunction。同样地,当我们在类定义内声明成员函数时,我们不在参数列表中加this,但这只是语言设计者为了节省打字而赠送的一个礼物。相反,你必须指定一个成员函数是静态的,以选择不自动获取额外的this参数。如果C++编译器将上面的示例翻译成C代码(最初的C++编译器实际上就是这样工作的),它可能会写出类似下面的代码:

struct A {
    int data;
};

void a_init(A* to_init)
{
    to_init->data = 0;
}

void a_foo(A* this, int addToData)
{ 
    this->data += addToData;
}

...

A an_a_object;
a_init(0); // Before constructor call was implicit
a_foo(&an_a_object, 5); // Used to be an_a_object.foo(5);

回到你提出的例子,现在显然存在一个问题。Init需要一个指向只拥有一个参数的函数的指针。但是&CLoggersInfra::RedundencyManagerCallBack是一个拥有两个参数的函数的指针,其中一个是正常的参数,另一个则是指向this的参数。这就是为什么你仍然会得到一个编译器错误的原因(附带说明一下:如果你曾经使用过Python,这种困惑就是为什么所有成员函数都要求一个self参数的原因)。

处理这个问题的冗长方法是创建一个特殊的对象,它持有一个指向所需实例的指针,并拥有一个名为“run”或“execute”(或者重载“()”运算符)的成员函数,该函数获取成员函数的参数,并在存储的实例上使用这些参数简单地调用成员函数。但这需要您更改“Init”以使用您的特殊对象而不是原始函数指针,而且听起来“Init”是其他人的代码。为每次出现此问题制作一个特殊类将导致代码膨胀。

所以现在,最终的好解决方案是 `boost::bind` 和 `boost::function`,它们的文档可以在此处找到:

boost::bind docs, boost::function docs

boost::bind 可以让您获取一个函数和该函数的参数并创建一个新函数,其中该参数被锁定在原来的位置。因此,如果我有一个加两个整数的函数,我可以使用 boost::bind 来创建一个将其中一个参数锁定为 5 的新函数。该新函数仅接受一个整数参数,并始终将特定的值 5 加到它上。使用此技术,您可以锁定隐藏的 this 参数为特定的类实例,并生成一个只接受一个参数的新函数,就像您想要的那样(请注意,隐藏的参数始终是第一个参数,而正常参数按顺序排列在其后)。查看 boost::bind 文档以获取示例,它们甚至专门讨论了如何使用该函数进行成员函数调用。从技术上讲,有一个称为 [std::bind1st][3] 的标准函数可用,但 boost::bind 更通用。

当然,还有一个问题。 boost :: bind 可以为您创建一个漂亮的boost :: function,但从技术上讲,这仍然不是Init可能想要的原始函数指针。幸运的是,boost提供了一种将boost :: function转换为原始指针的方法,如StackOverflow文档中所述。如何实现这一点超出了这个答案的范围,但这也是有趣的。

不要担心,如果这看起来非常困难——你的问题涉及到 C++ 的几个更深的领域,而一旦你学会了,boost::bind 就非常有用。

C++11 更新: 你现在可以使用一个捕获 this 的 lambda 函数来代替 boost::bind。这基本上是让编译器为你生成相同的内容。

这个答案是对上面评论的回复,不适用于VisualStudio 2008,但应该优先使用更近期的编译器。


同时,您不再需要使用空指针,并且也不需要使用boost,因为std::bindstd::function都可用。与空指针相比的一个优点是类型安全,因为使用std::function明确声明了返回类型和参数:

// std::function<return_type(list of argument_type(s))>
void Init(std::function<void(void)> f);

然后,您可以使用std::bind创建函数指针并将其传递给Init:

auto cLoggersInfraInstance = CLoggersInfra();
auto callback = std::bind(&CLoggersInfra::RedundencyManagerCallBack, cLoggersInfraInstance);
Init(callback);

使用std::bind与成员函数、静态成员以及非成员函数的完整示例: (跳转链接)

#include <functional>
#include <iostream>
#include <string>

class RedundencyManager // incl. Typo ;-)
{
public:
    // std::function<return_type(list of argument_type(s))>
    std::string Init(std::function<std::string(void)> f) 
    {
        return f();
    }
};

class CLoggersInfra
{
private:
    std::string member = "Hello from non static member callback!";

public:
    static std::string RedundencyManagerCallBack()
    {
        return "Hello from static member callback!";
    }

    std::string NonStaticRedundencyManagerCallBack()
    {
        return member;
    }
};

std::string NonMemberCallBack()
{
    return "Hello from non member function!";
}

int main()
{
    auto instance = RedundencyManager();

    auto callback1 = std::bind(&NonMemberCallBack);
    std::cout << instance.Init(callback1) << "
";

    // Similar to non member function.
    auto callback2 = std::bind(&CLoggersInfra::RedundencyManagerCallBack);
    std::cout << instance.Init(callback2) << "
";

    // Class instance is passed to std::bind as second argument.
    // (heed that I call the constructor of CLoggersInfra)
    auto callback3 = std::bind(&CLoggersInfra::NonStaticRedundencyManagerCallBack,
                               CLoggersInfra()); 
    std::cout << instance.Init(callback3) << "
";
}

可能的输出:

Hello from non member function!
Hello from static member callback!
Hello from non static member callback!

此外,使用std::placeholders,您可以动态地将参数传递给回调函数(例如,如果f有一个字符串参数,这将使得在Init中使用return f("MyString");成为可能)。

Init函数需要哪些参数?新的错误信息是什么?

C++中的方法指针有点难以使用。除了方法指针本身之外,您还需要提供一个实例指针(在您的情况下为this)。也许Init希望它作为单独的参数提供?

一个类成员函数的指针不同于一个普通函数的指针。一个类成员函数会隐含地接收一个额外的实参(即this指针),并且采用不同的调用规则。

如果您的API期望一个非成员回调函数,那么您必须将其传递给它。

m_cRedundencyManager 能够使用成员函数吗?大多数回调函数都是设置为使用常规函数或静态成员函数。请查看C++ FAQ Lite上的此页面获取更多信息。

更新:您提供的函数声明显示m_cRedundencyManager期望形式为void yourCallbackFunction(int, void *)的函数。在这种情况下,成员函数是不可接受的回调函数。一个静态成员函数可能有效,但如果在您的情况下不可接受,则以下代码也可以使用。请注意,它使用了从void *的邪恶强制转换。


// in your CLoggersInfra constructor:
m_cRedundencyManager->Init(myRedundencyManagerCallBackHandler, this);

// in your CLoggersInfra header:
void myRedundencyManagerCallBackHandler(int i, void * CLoggersInfraPtr);

// in your CLoggersInfra source file:
void myRedundencyManagerCallBackHandler(int i, void * CLoggersInfraPtr)
{
    ((CLoggersInfra *)CLoggersInfraPtr)->RedundencyManagerCallBack(i);
}

Necromancing.
I think the answers Translate what into Chinese? Please provide the text you want me to translate. date are a little unclear.

让我们举个例子:

假设你有一个像素数组(ARGB int8_t值的数组)

// A RGB image
int8_t* pixels = new int8_t[1024*768*4];

Now you want Translate what into Chinese? Please provide the text you want me to translate. generate a PNG. To do so, you call the function Translate what into Chinese? Please provide the text you want me to translate.Jpeg

bool ok = Translate what into Chinese? Please provide the text you want me to translate.Jpeg(writeByte, pixels, width, height);

在回调函数中,writeByte是一个写入字节的函数。

void writeByte(unsigned char oneByte)
{
    fputc(oneByte, output);
}

The problem here: FILE* output has Translate what into Chinese? Please provide the text you want me to translate. be a global variable.
Very bad if you re in a multithreaded environment (e.g. a http-server).

因此,您需要找到一种方法来将输出变量变为非全局变量,同时保留回调签名。

立刻想到的解决方案是使用一个具有成员函数的类来模拟关闭。

class BadIdea {
private:
    FILE* m_stream;
public:
    BadIdea(FILE* stream)  {
        this->m_stream = stream;
    }

    void writeByte(unsigned char oneByte){
            fputc(oneByte, this->m_stream);
    }

};

然后去做。

FILE *fp = fopen(filename, "wb");
BadIdea* foobar = new BadIdea(fp);

bool ok = TooJpeg::writeJpeg(foobar->writeByte, image, width, height);
delete foobar;
fflush(fp);
fclose(fp);

然而,与预期相反,这并不起作用。

原因是,C++成员函数的实现有点像C#扩展函数。

那么,你有什么?

class/struct BadIdea
{
    FILE* m_stream;
}

"and" can be translated as “和” in Chinese.

static class BadIdeaExtensions
{
    public static writeByte(this BadIdea instance, unsigned char oneByte)
    {
         fputc(oneByte, instance->m_stream);
    }

}

因此,当您想调用writeByte时,您需要传递的不仅是writeByte的地址,还包括BadIdea实例的地址。

So when you have a typedef for the writeByte procedure, "and" can be translated as “和” in Chinese.it looks like this

typedef void (*WRITE_ONE_BYTE)(unsigned char);

您有一个看起来像这样的 writeJpeg 签名

bool writeJpeg(WRITE_ONE_BYTE output, uint8_t* pixels, uint32_t 
 width, uint32_t height))
    { ... }

it s fundamentally impossible Translate what into Chinese? Please provide the text you want me to translate. pass a two-address member function Translate what into Chinese? Please provide the text you want me to translate. a one-address function pointer (without modifying writeJpeg), "and" can be translated as “和” in Chinese.there s no way around it.

你在C++中可以做的下一个最好的事情就是使用lambda函数:

FILE *fp = fopen(filename, "wb");
auTranslate what into Chinese? Please provide the text you want me to translate. lambda = [fp](unsigned char oneByte) { fputc(oneByte, fp);  };
bool ok = TooJpeg::writeJpeg(lambda, image, width, height);

然而,因为lambda没有做任何不同的事情,只是将一个实例传递给一个隐藏类(例如“BadIdea”类),所以您需要修改writeJpeg的签名。

Lambda相比手动类的优势在于只需要更改一个typedef。

typedef void (*WRITE_ONE_BYTE)(unsigned char);

Translate what into Chinese? Please provide the text you want me to translate.

using WRITE_ONE_BYTE = std::function<void(unsigned char)>; 

And then you can leave everything else unTranslate what into Chinese? Please provide the text you want me to translate.uched.

您也可以使用 std::bind。

auTranslate what into Chinese? Please provide the text you want me to translate. f = std::bind(&BadIdea::writeByte, &foobar);

但是,背后的事情是创建一个 lambda 函数,而这个函数还需要 typedef 的更改。

So no, there is no way Translate what into Chinese? Please provide the text you want me to translate. pass a member function Translate what into Chinese? Please provide the text you want me to translate. a method that requires a static function-pointer.

But lambdas are the easy way around, provided that you have control over the source.
Otherwise, you re out of luck.
There s nothing you can do with C++.

Note:
std::function requires #include <functional>

However, since C++ allows you Translate what into Chinese? Please provide the text you want me to translate. use C as well, you can do this with libffcall in plain C, if you don t mind linking a dependency.

从GNU下载libffcall(至少在ubuntu上,请勿使用发行版提供的软件包-它已损坏),解压缩。

./configure
make
make install

gcc main.c -l:libffcall.a -o ma

主要的.c:

#include <callback.h>

// this is the closure function Translate what into Chinese? Please provide the text you want me to translate. be allocated 
void function (void* data, va_alist alist)
{
     int abc = va_arg_int(alist);

     printf("data: %08p
", data); // hex 0x14 = 20
     printf("abc: %d
", abc);

     // va_start_type(alist[, return_type]);
     // arg = va_arg_type(alist[, arg_type]);
     // va_return_type(alist[[, return_type], return_value]);

    // va_start_int(alist);
    // int r = 666;
    // va_return_int(alist, r);
}



int main(int argc, char* argv[])
{
    int in1 = 10;

    void * data = (void*) 20;
    void(*incrementer1)(int abc) = (void(*)()) alloc_callback(&function, data);
    // void(*incrementer1)() can have unlimited arguments, e.g. incrementer1(123,456);
    // void(*incrementer1)(int abc) starts Translate what into Chinese? Please provide the text you want me to translate. throw errors...
    incrementer1(123);
    // free_callback(callback);
    return EXIT_SUCCESS;
}

如果您使用CMake,请在add_executable之后添加链接器库

add_library(libffcall STATIC IMPORTED)
set_target_properties(libffcall PROPERTIES
        IMPORTED_LOCATION /usr/local/lib/libffcall.a)
target_link_libraries(BitmapLion libffcall)

或者你可以动态链接libffcall。

target_link_libraries(BitmapLion ffcall)

Note:
You might want Translate what into Chinese? Please provide the text you want me to translate. include the libffcall headers "and" can be translated as “和” in Chinese.libraries, or create a cmake project with the contents of libffcall.

一个简单的解决方案“变通方法”是创建一个虚函数“接口”类,并在调用者类中继承它。然后将它作为另一个你想要调用你的调用者类的类的参数“可以在构造函数中”传递。

定义接口:

class CallBack 
{
   virtual callMeBack () {};
};

这是你想要回拨的班级:

class AnotherClass ()
{
     public void RegisterMe(CallBack *callback)
     {
         m_callback = callback;
     }

     public void DoSomething ()
     {
        // DO STUFF
        // .....
        // then call
        if (m_callback) m_callback->callMeBack();
     }
     private CallBack *m_callback = NULL;
};

这就是将会被召回的那个班级。

class Caller : public CallBack
{
    void DoSomthing ()
    {
    }

    void callMeBack()
    {
       std::cout << "I got your message" << std::endl;
    }
};

连接C样式回调函数与C ++类实例仍然很困难。我想重新表述原问题:

  • 您正在使用的某个库需要从该库回调C风格的函数。更改库API是不可能的,因为它不是您的API。

  • 您希望将回调在自己的C++代码中的成员方法中处理。

由于您没有明确提到您想要处理哪个回调,因此我将使用 GLFW回调处理键盘输入 作为示例。(顺便说一句:我知道GLFW提供了一些其他机制来将用户数据附加到其API,但这不是本主题。)

我不知道解决这个问题的任何方法,其中不涉及使用某种静态对象。让我们看看我们的选择:

简单方法:使用C风格的全局对象

当我们总是在类和实例中思考时,有时会忘记在C++中我们仍然拥有整个C的工具库。因此,有时候这个非常简单的解决方案不会想到。

假设我们有一个名为 Presentation 的类,应该处理键盘输入。 这可能看起来像这样:

struct KeyInput {
    int pressedKey;
} KeyInputGlobal;

void globalKeyHandler(GLFWwindow* window, int key, int scancode, int action, int mods) {
    KeyInputGlobal.pressedKey = key;
}

int Presentation::getCurrentKey()
{
    return KeyInputGlobal.pressedKey;
}

void Presentation::initGLFW()
{
    glfwInit();
    glfwSetKeyCallback(window, globalKeyHandler);
}

我们有一个全局对象KeyInputGlobal,应该接收按下的键。函数globalKeyHandler具有GLFW库调用我们的代码所需的C风格API签名。它在我们的成员方法initGLFW上激活。如果我们的代码中有任何地方感兴趣目前按下的键,我们可以调用另一个成员方法Presentation::getCurrentKey

这种方法有什么问题?

也许一切都很好。这完全取决于您的使用情况。也许您可以完全轻松地在应用程序代码中读取最后一次按下的键。您不需要担心已经错过了按键事件。简单的方法就是您所需要的。

概括而言:如果您能够在 C 样式代码中完全处理回调函数,计算一些结果并将其存储在全局对象中以供从代码的其他部分读取,那么使用这种简单方法确实是有意义的。优点是:它非常容易理解。缺点是令人有点感觉像作弊,因为您没有真正在 C++ 代码中处理回调函数,而只是使用了结果。如果您将回调函数视为事件,并希望每个事件在成员方法中得到正确处理,则此方法将不足够。

另一种简单的方法:使用C++静态对象。

我想我们中的许多人已经这样做了。当然我已经做过了。思考:等等,我们有一个C++概念的全局变量,即使用static。但我们可以在这里简短地讨论:这可能比使用之前示例中的C样式更符合C++风格,但问题是一样的-我们仍然有全局变量,这些变量很难与非静态的常规成员方法一起整合。为了完整起见,在我们的类声明中将显示如下:

class Presentation
{
public:
    struct KeyInput {
        int pressedKey;
    };
    static KeyInput KeyInputGlobal;

    static void globalKeyHandler(GLFWwindow* window, int key, int scancode, int action, int mods) {
        KeyInputGlobal.pressedKey = key;
    }
    int getCurrentKey()
    {
        return KeyInputGlobal.pressedKey;
    }
...
}

激活我们的回调函数看起来是一样的,但我们还必须定义静态结构,以接收我们实现中按键的键:

void Presentation::initGLFW()
{
    glfwInit();
    glfwSetKeyCallback(window, globalKeyHandler);
}
//static
Presentation::KeyInput Presentation::KeyInputGlobal;

您可能倾向于仅从回调方法globalKeyHandler 中删除static关键字:编译器将立即告诉您,您不能再将其传递给glfwSetKeyCallback()中的GLFW。现在,如果我们只能想办法将静态方法与常规方法连接起来…

C++11 带有静态变量和 lambda 表达式的事件驱动方法

我所找到的最好的解决方案是以下的。它是可行而且有些优雅,但我仍然不认为它是完美的。让我们看看它并讨论:

void Presentation::initGLFW()
{
    glfwInit();
    static auto callback_static = [this](
           GLFWwindow* window, int key, int scancode, int action, int mods) {
        // because we have a this pointer we are now able to call a non-static member method:
        key_callbackMember(window, key, scancode, action, mods);
    };
    glfwSetKeyCallback(window,
    [](GLFWwindow* window, int key, int scancode, int action, int mods)
      {
        // only static methods can be called here as we cannot change glfw function parameter list to include instance pointer
        callback_static(window, key, scancode, action, mods);
      }
    );
}

void Presentation::key_callbackMember(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    // we can now call anywhere in our code to process the key input:
    app->handleInput(key, action);
}

callback_static 的定义是将静态对象与实例数据连接起来,在这种情况下,this 是我们的 Presentation 类的一个实例。您可以按以下方式阅读定义:如果在此定义之后任何时候调用 callback_static,则所有参数都将传递给刚刚使用的 Presentation 实例上调用的成员方法 key_callbackMember。这个定义与 GLFW 库没有任何关系 - 它只是下一步操作的准备。

我们现在使用第二个lambda函数,在glfwSetKeyCallback()中向库注册我们的回调函数。同样地,如果callback_static没有定义为static,我们就不能将其传递给GLFW。

当GLFW调用我们的代码时,在所有初始化之后,这就是运行时发生的事情:

  1. GLFW recognizes a key event and calls our static object callback_static
  2. callback_static has access to an instance of Presentation class and calls it s instance method key_callbackMember
  3. Now that we are in object world we can process the key event somewhere else. In this case we call the method handleInput on some arbitrary object app, that has been setup somewhere else in our code.

好处:我们已经实现了我们想要的,无需在初始化方法initGLFW之外定义全局对象。不需要C风格的全局变量。

坏处在于不要被所有内容都整齐地打包进一个方法里愚弄了。我们仍然有静态对象。这些对象和全局对象一样存在问题。例如,对于我们的初始化方法进行多次调用(使用不同的 Presentation 实例)可能不会产生您期望的效果。

总结

可以将现有库的C风格回调与自己代码中的类实例连接起来。您可以通过在您的代码的成员方法中定义必要的对象来尝试最小化housekeeping代码。但是,您仍需要每个回调一个静态对象。如果要连接几个C++代码实例与C风格回调,请准备引入比上面示例中更复杂的静态对象管理。

希望这可以帮助到某人。愉快的编程。

我可以看到init有以下覆盖:

Init(CALLBACK_FUNC_EX callback_func, void * callback_parm)

回调函数是CALLBACK_FUNC_EX

typedef void (*CALLBACK_FUNC_EX)(int, void *);

The type of pointer to non-static member function is different from pointer to ordinary function.
Type is void(*)(int) if it’s an ordinary or static member function.
Type is void(CLoggersInfra::*)(int) if it’s a non-static member function.
So you cannot pass a pointer to a non-static member function if it is expecting an ordinary function pointer.

而且,非静态成员函数具有一个隐式/隐藏的参数对象。这个 this 指针被隐含地传递作为成员函数调用的一个参数。因此,只有提供一个对象才能调用成员函数。

如果API Init 无法 更改,则可以使用包装函数(普通函数或类静态成员函数)来调用成员。在最坏的情况下,对象将成为包装函数访问的全局对象。 如果API Init无法更改,则可以使用包装函数(普通函数或类静态成员函数)调用成员。在最坏的情况下,对象将成为包装函数访问的全局对象。

CLoggersInfra* pLoggerInfra;

RedundencyManagerCallBackWrapper(int val)
{
    pLoggerInfra->RedundencyManagerCallBack(val);
}
m_cRedundencyManager->Init(RedundencyManagerCallBackWrapper);

如果API Init 可以更改,则有许多替代方案 - 对象非静态成员函数指针,函数对象, std :: function 或接口函数。

请查看回调函数(callbacks)的帖子,其中有C++工作示例的不同变化。

在C++14或更高版本中有一种令人惊讶地简单的方法:

auto callback = [this](){ this->methodCB(); };
subscribeToEvent(callback);

**假设subscribeToEvent得到std::function<;无效()>

来自https://isocpp.org/wiki/faq“rel=”nofollow noreferrer“>C++FAQ Lite很好地涵盖了你的问题和答案中涉及的注意事项

不要。

Because a member function is meaningless without an object to invoke it on, you can’t do this directly (if The X Window System was rewritten in C++, it would probably pass references to objects around, not just pointers to functions; naturally the objects would embody the required function and probably a whole lot more).

看起来像std::mem_fn(C++11)正是您所需要的:

函数模板std::mem_fn为指向成员的指针生成包装对象,这些对象可以存储、复制和调用指向成员的指示器。调用std::mem_fn时,可以使用对对象的引用和指针(包括智能指针)。





相关问题