3 回答
TA贡献1826条经验 获得超6个赞
简而言之,std::function除非有理由不要使用。
函数指针的缺点是无法捕获某些上下文。例如,您将无法通过lambda函数作为捕获某些上下文变量的回调(但是如果不捕获任何上下文变量,它将起作用)。因此也不可能调用对象的成员变量(即非静态的),因为this需要捕获对象(-pointer)。(1)
std::function(因为C ++ 11)主要用于存储函数(将其传递就不需要存储它)。因此,如果要将回调存储在例如成员变量中,则可能是最佳选择。但是,如果您不存储它,那么它是一个不错的“首选”,尽管它的缺点是在调用时会引入一些(非常小的)开销(因此,在性能非常关键的情况下,这可能是个问题,但在大多数情况下它不应该)。这是非常“通用的”:如果您非常关心一致且易读的代码,又不想考虑所做的每一个选择(即想保持简单),请使用std::function传递的每个函数。
考虑第三个选项:如果您要实现一个小的函数,然后通过提供的回调函数报告某些内容,请考虑一个template参数,该参数可以是任何可调用的对象,即函数指针,函子,lambda,一个std::function缺点是这里的(外部)函数成为模板,因此需要在标头中实现。另一方面,您得到的好处是可以内联对回调的调用,因为(外部)函数的客户端代码“看到”了对回调的调用,将提供确切的类型信息。
具有模板参数的版本的示例(对于C ++ 11之前的版本,请写&而不是&&):
template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
...
callback(...);
...
}
正如您在下表中看到的,它们都有优点和缺点:
+-------------------+--------------+---------------+----------------+
| | function ptr | std::function | template param |
+===================+==============+===============+================+
| can capture | no(1) | yes | yes |
| context variables | | | |
+-------------------+--------------+---------------+----------------+
| no call overhead | yes | no | yes |
| (see comments) | | | |
+-------------------+--------------+---------------+----------------+
| can be inlined | no | no | yes |
| (see comments) | | | |
+-------------------+--------------+---------------+----------------+
| can be stored | yes | yes | no(2) |
| in class member | | | |
+-------------------+--------------+---------------+----------------+
| can be implemented| yes | yes | no |
| outside of header | | | |
+-------------------+--------------+---------------+----------------+
| supported without | yes | no(3) | yes |
| C++11 standard | | | |
+-------------------+--------------+---------------+----------------+
| nicely readable | no | yes | (yes) |
| (my opinion) | (ugly type) | | |
+-------------------+--------------+---------------+----------------+
(1)存在克服此限制的解决方法,例如,将其他数据作为进一步的参数传递给您的(外部)函数:myFunction(..., callback, data)will call callback(data)。这就是C样式的“带参数的回调”,这在C ++中是可行的(并且在WIN32 API中大量使用),但是应避免使用,因为我们在C ++中有更好的选择。
(2)除非我们在谈论类模板,否则存储函数的类就是模板。但这意味着在客户端,函数的类型决定了存储回调的对象的类型,这在实际用例中几乎从来不是一个选择。
(3)对于C ++ 11之前的版本,请使用 boost::function
TA贡献1796条经验 获得超10个赞
使用std::function存储任意调用对象。它允许用户提供回调所需的任何上下文。一个普通的函数指针没有。
如果由于某种原因(也许是因为您想要C兼容的API)而确实需要使用普通函数指针,则应添加一个void * user_context参数,以便至少有可能(尽管不方便)访问不直接传递给参数的状态。功能。
- 3 回答
- 0 关注
- 1542 浏览
添加回答
举报