在讨论中我们有here我正在玩弄着传球手。 C ++ STL将仿函数作为值传递(见std::for_each
,std::find_if
,std::transform
)
所以宣告我的就是这样。
template<typename F>
void call_me(F f)
{
f();
}
现在,调用call_me(ftor{})
可能会调用ftor
的复制构造函数(很可能是复制省略,所以不是这样)。但是ftor f{}; call_me(f);
会导致复制。如果ftor
包含大量数据,则可能是个问题。
我们通过将其作为const引用(void call_me(const F& f)
)传递来去除不需要的副本来改进它。只要ftor::operator()
为const
,这就没问题了。如果不是,则调用call_me
将导致编译错误(丢失const
个限定符。)
那么,为什么要使用const引用,只使用引用(void call_me(F& f)
)。这很好,但是对于第一种情况call_me(ftor{})
它不起作用,因为将r值转换为(非常量)l值引用是无效的。
将f
声明为转发引用(void call_me(F&& f)
)似乎适用于所有情况。我相信,这可以归功于参考折叠。
那么,为什么模板化仿函数不作为STL函数中的转发引用传递?
答案 0 :(得分:11)
为什么模板化仿函数不作为STL函数中的r值引用传递?
首先,他们转发引用,而非rvalue引用。
那就像许多&#34;为什么&#34;关于语言设计的一般问题,答案可能只是:因为没有人提出过这种改变(见how to submit a proposal)。我怀疑传递到标准库算法的大量函数对象要么是lambdas,要么是无状态的,要么是非常便宜的可复制的。此外,如果您有这样一个昂贵的对象,您可以随时将其转换为便宜的可复制对象:
call_me(std::ref(huge_object));
最后,其中一些算法依赖于将这些函数对象传递给其他助手。如果算法只是假设函数对象是&#34; free&#34;复制,这使代码变得容易。如果我们在这里引入rvalues的可能性,这会增加另一层需要处理的问题 - 我们只是传递参考值吗?那些具有ref-qualified operator()
的函数对象呢?
上述的某些组合可能解释了为什么,例如,它仍然是:
template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt, InputIt, UnaryPredicate );
而不是
template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt, InputIt, UnaryPredicate&& );