Ram*_*ngh 13 c++ stl functor function-object
这个工作的关键原因是for_each()实际上并没有假设 它的第三个参数是一个函数.它只是假设它的第三个参数是可以用适当的参数调用的东西.适当定义的对象与 - 函数一样 - 并且通常比 - 更好.例如,内联类的应用程序操作符比内联作为函数指针传递的函数更容易.因此,函数对象通常比普通函数执行得更快.具有应用程序运算符(第11.9节)的类的对象称为类似函数的对象,仿函数或简称为函数对象.
[Stroustrup,C++第3版,18.4-最后一段]
我一直认为operator()调用就像在运行时调用函数一样.它与普通函数调用有什么不同?
为什么内联应用程序操作符比正常函数更容易?
它们如何比函数调用更快?
Eam*_*nne 10
通常,仿函数被传递给模板化函数 - 如果你这样做,那么传递一个"真实"函数(即一个函数指针)或一个仿函数(即一个带有重载的类)并不重要operator().本质上,它们都有一个函数调用操作符,因此是编译器可以实例化for_each模板的有效模板参数. 这意味着for_each要么通过传递的仿函数的特定类型实例化,要么传递特定类型的函数指针. 正是在这种专业化中,仿函数可以胜过函数指针.
毕竟,如果你传递一个函数指针,那么参数的编译类型就是 - 一个函数指针.如果for_each本身没有内联,则for_each编译此特定实例以调用opaque函数指针 - 毕竟,编译器如何内联函数指针?它只是知道它的类型,而不是它那种类型的功能实际上是通过-至少,除非它可以使用优化时,非本地信息,这是很难的事情.
但是,如果传递仿函数,则该仿函数的编译时类型用于实例化for_each模板.在这样做时,您可能正在传递一个简单的非虚拟类,只有一个适当的实现operator().因此,当编译器遇到operator()对它的调用时,确切地知道哪个实现意味着 - 该仿函数的唯一实现 - 现在它可以内联.
如果您的仿函数使用虚拟方法,潜在的优势就会消失.当然,一个仿函数是一个类,你可以用它来做各种其他低效的事情.但是对于基本情况,这就是为什么编译器比函数指针调用更容易优化和内联函子调用.
函数指针不能内联,因为编译编译for_each器时只有函数的类型而不是函数的标识.相比之下,仿函数可以内联,因为即使编译器只具有仿函数类型,类型通常也足以唯一地标识仿函数的operator()方法.
考虑以下两个模板实例:
std::for_each<class std::vector<int>::const_iterator, class Functor>(...)
Run Code Online (Sandbox Code Playgroud)
和
std::for_each<class std::vector<int>::const_iterator, void(*)(int)>(...)
Run Code Online (Sandbox Code Playgroud)
因为第一个是为每种类型的函数对象定制的,并且因为operator()通常是内联定义的,所以编译器可以自行决定选择内联调用。
在第二种情况下,编译器将为相同签名的所有函数实例化一次模板,因此,它无法轻松内联调用。
现在,智能编译器或许能够确定在编译时调用哪个函数,尤其是在这样的场景中:
std::for_each(v.begin(), v.end(), &foo);
Run Code Online (Sandbox Code Playgroud)
并且仍然通过生成自定义实例而不是前面提到的单个通用实例来内联函数。
| 归档时间: |
|
| 查看次数: |
2863 次 |
| 最近记录: |