[英]using a std::function or a forwarding reference as general-purpose callable object input parameter of a higher-order function?
I was wondering about the main differences, pros and cons in writing a higher order function taking, as input parameter, a std::function
or a forwarding reference , eg template<typename F> void hof(F&& fun);
我想知道编写高阶函数的主要区别,优点和缺点,作为输入参数, std::function
或转发引用 ,例如template<typename F> void hof(F&& fun);
. 。 Obviously, the former is more strict than the latter in that it specifies the function type that the input callable object has to conform to. 显然,前者比后者更严格 ,因为它指定了输入可调用对象必须符合的函数类型 。
std::function
often has a significant run-time overhead. std::function
通常具有显着的运行时开销。 Passing a generic callable object through a template
parameter avoids std::function
's indirection costs and allows the compiler to aggressively optimize . 通过template
参数传递通用可调用对象可以避免std::function
的间接成本,并允许编译器积极地进行优化 。
I wrote some simple benchmarks for lambda recursion (Y-combinator vs std::function
) at the end of this article . 我在本文末尾为lambda递归(Y-combinator vs std::function
)编写了一些简单的基准测试。 std::function
always generates at least 3.5x times more assembly than a non-polymorphic Y-combinator implementation. 与非多态Y组合器实现相比, std::function
总是生成至少3.5倍的程序集。 This is a decent example that shows how std::function
can be more expensive than a template
parameter. 这是一个很好的例子 ,它显示了std::function
如何比template
参数更昂贵。
I suggest playing around on gcc.godbolt.org to see assembly differences between the two techniques. 我建议在gcc.godbolt.org上玩 ,看看两种技术之间的装配差异。
Here's an example I just came up with : 这是我刚才提出的一个例子:
#if defined(STDFN)
void pass_by_stdfn(std::function<void()> f)
{
f();
}
#else
template <typename TF>
void pass_by_template(TF&& f)
{
f();
}
#endif
volatile int state = 0;
int main()
{
#if defined(STDFN)
pass_by_stdfn([i = 10]{ state = i; });
#else
pass_by_template([i = 10]{ state = i; });
#endif
}
With STDFN
not defined , the generated assembly is: 与STDFN
没有定义 ,生成的汇编是:
main:
mov DWORD PTR state[rip], 10
xor eax, eax
ret
state:
.zero 4
With STDFN
defined , the generated assembly is 48 lines long. 定义了STDFN
,生成的程序集长度为48行。
std::function
has a lot of pros, but it has also a series of cons that you must take into account. std::function
有很多专业人士,但它也有一系列缺点,你必须考虑到。
As an example: 举个例子:
The callable object should be copy constructible. 可调用对象应该是可复制构造的。
In other terms, this compiles: 换句话说,这编译:
#include <functional> #include <utility> #include <memory> template<typename F> void func(F &&f) { std::forward<F>(f)(); } int main() { func([ptr = std::make_unique<int>()](){}); }
But this does not: 但这不是:
#include <functional> #include <utility> #include <memory> void func(std::function<void(void)> f) { f(); } int main() { func([ptr = std::make_unique<int>()](){}); }
Even though (emphasis mine): 即使(强调我的):
Implementations are encouraged to avoid the use of dynamically allocated memory for small callable objects, for example, where f's target is an object holding only a pointer or reference to an object and a member function pointer. 鼓励实现避免为小的可调用对象使用动态分配的内存,例如,f的目标是仅包含对象的指针或引用的对象以及成员函数指针。
You have no guarantees that you won't have allocations on the dynamic storage when they could be avoided, and you'll have allocations for sure in all the other cases. 您无法保证在可以避免的情况下不会对动态存储进行分配,并且您将在所有其他情况下确保分配。
When you construct a std::function
, the constructor may throw a bad_alloc
. 构造std::function
,构造函数可能会抛出bad_alloc
。
... Probably we can continue, but it doesn't worth it, you got the point. ......可能我们可以继续,但它不值得,你明白了。
std::function
s are in incredible useful tool, but you should use them when you need them. std::function
s是一个非常有用的工具,但你应该在需要时使用它们。
As an example, if you plan to store your function somewhere, likely you will end up using a std::function
. 例如,如果您计划将函数存储在某个位置,可能最终会使用std::function
。 On the other side, if you plan to accept a callable object and invoke it on the fly, probably you won't use a std::function
. 另一方面,如果您计划接受可调用对象并在运行中调用它,可能您不会使用std::function
。
These are only a few examples, a golden rule doesn't exist unfortunately. 这些仅仅是几个例子,不幸的是,黄金法则不存在。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.