将仿函数而不是函数传递给 STL 是否仍然可取?
Is it still advisable to pass functors to STL instead of functions?
在 Effective STL 中,Scott Meyers 早在 2001 年就建议:
Item 46: Consider function objects instead of functions as algorithm parameters
在上述章节中,他继续解释 inline operator()
可以内联到算法主体中,但传递函数通常不能。这是因为我们实际上传递了一个函数指针。
为了支持这一点,我 seem to remember 如果某个函数的地址被占用,则无法内联该函数。
这里有两个问题。首先,C++14 是否仍然如此?
如果是:
- 为什么没有自动执行此操作的机制(动机:声明一个函子比声明一个函数更不直接和可读)。
- 没有捕获的 lambda 可以转换为函数指针,而捕获的 lambda 只能作为函子传递。这是否意味着我们只需要为所述优化捕获一些东西?
Is this still true with C++14?
取决于编译器是否可以内联整个算法。如果可以,那么它也可能内联函数调用。如果不是,那么该函数可能无法内联,因为这种情况下的算法是使用函数指针类型实例化的,因此必须能够处理该类型的所有函数指针。
例如,g++ 可以内联像 std::transform
这样的简单算法,但不能内联 std::sort
。
A lambda without capture is convertible to function pointer, while a capturing lambda can only be passed as a functor. Does this mean we need to capture something only for the sake of stated at top optimization?
没有。没有捕获的 lambda 仍然是一个函子;该算法使用闭包类型(lambda 的类型)而不是函数指针类型进行实例化。
In support of that I seem to remember that if a function's address is ever taken, the function can't be inlined.
你读错了。如果编译器可以跟踪函数指针,则可以将函数内联到任何直接调用点和任何间接调用点。 GCC 联机帮助页所说的是,内联到每个调用站点的函数根本不会作为单独的函数发出(从而减少二进制大小),除非 它的地址被占用。
Firstly, is this still true with C++14?
是的。当然,现在您通常会编写 lambda 而不是手工制作的仿函数。
Why is there no mechanism to do this automatically.
这是类型系统的问题。具有给定签名的所有函数都具有相同的类型。因此,传递函数指针的算法被实例化为一个具体的函数,其代码在C++的编译模型中只存在一次。
当然,优化器仍然可以针对一个特定参数专门化函数,但这是一种比仅内联仿函数更高级的优化。所以是的,有一种机制,它不太可能被使用。
Does this mean we need to capture something only for the sake of stated at top optimization?
没有。向函数指针的转换是 可能的,但除非您显式调用它,否则当您将 lambda 传递给算法时,它不会完成。
在 Effective STL 中,Scott Meyers 早在 2001 年就建议:
Item 46: Consider function objects instead of functions as algorithm parameters
在上述章节中,他继续解释 inline operator()
可以内联到算法主体中,但传递函数通常不能。这是因为我们实际上传递了一个函数指针。
为了支持这一点,我 seem to remember 如果某个函数的地址被占用,则无法内联该函数。
这里有两个问题。首先,C++14 是否仍然如此?
如果是:
- 为什么没有自动执行此操作的机制(动机:声明一个函子比声明一个函数更不直接和可读)。
- 没有捕获的 lambda 可以转换为函数指针,而捕获的 lambda 只能作为函子传递。这是否意味着我们只需要为所述优化捕获一些东西?
Is this still true with C++14?
取决于编译器是否可以内联整个算法。如果可以,那么它也可能内联函数调用。如果不是,那么该函数可能无法内联,因为这种情况下的算法是使用函数指针类型实例化的,因此必须能够处理该类型的所有函数指针。
例如,g++ 可以内联像 std::transform
这样的简单算法,但不能内联 std::sort
。
A lambda without capture is convertible to function pointer, while a capturing lambda can only be passed as a functor. Does this mean we need to capture something only for the sake of stated at top optimization?
没有。没有捕获的 lambda 仍然是一个函子;该算法使用闭包类型(lambda 的类型)而不是函数指针类型进行实例化。
In support of that I seem to remember that if a function's address is ever taken, the function can't be inlined.
你读错了。如果编译器可以跟踪函数指针,则可以将函数内联到任何直接调用点和任何间接调用点。 GCC 联机帮助页所说的是,内联到每个调用站点的函数根本不会作为单独的函数发出(从而减少二进制大小),除非 它的地址被占用。
Firstly, is this still true with C++14?
是的。当然,现在您通常会编写 lambda 而不是手工制作的仿函数。
Why is there no mechanism to do this automatically.
这是类型系统的问题。具有给定签名的所有函数都具有相同的类型。因此,传递函数指针的算法被实例化为一个具体的函数,其代码在C++的编译模型中只存在一次。
当然,优化器仍然可以针对一个特定参数专门化函数,但这是一种比仅内联仿函数更高级的优化。所以是的,有一种机制,它不太可能被使用。
Does this mean we need to capture something only for the sake of stated at top optimization?
没有。向函数指针的转换是 可能的,但除非您显式调用它,否则当您将 lambda 传递给算法时,它不会完成。