为什么模板化仿函数作为值传递而不是转发参考

时间:2016-07-13 16:31:56

标签: c++ templates c++11

在讨论中我们有here我正在玩弄着传球手。 C ++ STL将仿函数作为值传递(见std::for_eachstd::find_ifstd::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函数中的转发引用传递?

1 个答案:

答案 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&& );