在 C++ 中实现回调函数时,是否仍应使用 C 风格的函数指针:
void (*callbackFunc)(int);
或者我应该使用 std::function:
std::function< void(int) > callbackFunc;
简而言之,std::function除非您有理由不使用,否则请使用。
std::function
函数指针的缺点是 无法捕获 某些上下文。例如,您将无法将 lambda 函数作为捕获某些上下文变量的回调传递(但如果它不捕获任何变量,它将起作用)。因此,调用对象的成员变量(即非静态)也是不可能的,因为this需要捕获对象(-pointer)。(1)
this
std::function(自 C++11 起)主要是 存储 一个函数(传递它不需要存储它)。因此,如果您想将回调存储在成员变量中,这可能是您的最佳选择。但是,如果您不存储它,它也是一个很好的“首选”,尽管它的缺点是在调用时会引入一些(非常小的)开销(因此在性能非常关键的情况下,它可能是一个问题,但在大多数情况下它不应该)。它非常“通用”:如果您非常关心一致和可读的代码,并且不想考虑您所做的每一个选择(即希望保持简单),请使用std::function您传递的每个函数。
考虑第三种选择:如果您要实现一个小函数,然后通过提供的回调函数报告某些内容,请考虑一个 模板参数 ,它可以是 任何可调用对象 ,即函数指针、仿函数、lambda, a std::function, … 缺点是您的(外部)函数成为模板,因此需要在标题中实现。另一方面,您可以获得对回调的调用可以内联的优势,因为您的(外部)函数的客户端代码“看到”对回调的调用将获得可用的确切类型信息。
带有模板参数的版本示例(写&而不是&&C++11 之前的版本):
&
&&
template <typename CallbackFunction> void myFunction(..., CallbackFunction && callback) { ... callback(...); ... }
如下表所示,它们都有其优点和缺点:
(1) 存在克服此限制的解决方法,例如将附加数据作为进一步参数传递给您的(外部)函数:myFunction(..., callback, data)将调用callback(data). 那是 C 风格的“带参数的回调”,这在 C 中是可能的(顺便说一句,在 WIN32 API 中大量使用),但应该避免,因为我们在 C 中有更好的选择。
myFunction(..., callback, data)
callback(data)
(2) 除非我们谈论的是类模板,即存储函数的类是模板。但这意味着在客户端,函数的类型决定了存储回调的对象的类型,这几乎不是实际用例的选项。
(3) 对于 C++11 之前的版本,使用boost::function
boost::function