为什么模板化函子作为值传递而不是转发引用
Why is templated functor passed as value and not forwarding reference
在我们这里的讨论中,我正在玩传递函子。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
有大量数据,则可能是个问题。
我们将通过将其作为常量引用(void call_me(const F& f)
)传递来改进它,以摆脱不需要的副本。只要ftor::operator()
const
就可以了。否则,对 call_me
的调用将导致编译错误(丢失const
限定符)。
那么,为什么要打扰常量引用,只使用引用(void call_me(F& f)
)。这很好,但它不适用于call_me(ftor{})
的第一种情况,因为将 r 值绑定到(非常量)l 值引用是无效的。
声明f
为转发引用(void call_me(F&& f)
)似乎在所有情况下都有效。我相信,这要归功于引用折叠。
那么,为什么模板化函子没有作为 STL 函数中的转发引用传递呢?
为什么模板化函子没有作为 STL 函数中的 r 值引用传递?
首先,它们是转发引用,而不是右值引用。
也就是说,就像许多关于语言设计的"为什么"问题一样,答案可以很简单:因为还没有人提出这个改变(参见如何提交提案)。我怀疑传递到标准库算法中的大量函数对象要么是 lambda,要么是无状态的,要么是极其便宜的可复制的。此外,如果你有一个如此昂贵的对象,你总是可以把它变成一个廉价的可复制的,用于算法的目的:
call_me(std::ref(huge_object));
最后,其中一些算法依赖于将这些函数对象传递给其他帮助程序。如果算法只是假设函数对象是"自由"复制的,这使得编码变得容易。如果我们在这里引入右值的可能性,这增加了另一层需要处理的问题 - 我们只是传递参考吗?具有 ref 限定operator()
的函数对象呢?
上述的某种组合可能解释了为什么,例如,它仍然是:
template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt, InputIt, UnaryPredicate );
而不是
template <class InputIt, class UnaryPredicate>
InputIt find_if(InputIt, InputIt, UnaryPredicate&& );
- 正在折叠转发引用
- 如何在模板中转发右值和左值引用
- 通过基类接受方法转发派生 UniquePtr 的右值会移动引用而不是复制
- C++ 何时使用常量引用而不是转发引用
- 为什么转发声明的好友类不能在类中引用?
- C++完美转发:如何避免悬空引用
- C++:通用(转发)引用中不允许常量
- 模板模板参数和转发引用
- 常量转发引用给出错误 C2440:"正在初始化":无法从"常量标准::字符串"转换为"常量标准::字符串 &&"
- 具有右值引用,而不是使用可变参数模板转发引用
- 自定义类型转换运算符在转发引用上调用时不起作用(当对象按值传递时有效)
- 如何从常量引用或通过转发模板临时构造对象
- 结构化绑定和转发引用是否混合良好?
- 如何声明接受转发引用并返回引用或副本的函数模板
- 间接转发引用
- 为什么调用转发引用构造函数而不是复制构造函数?
- 为什么 std::get 没有一个接受转发引用的签名
- 有没有办法在不引用其模板类型的情况下转发声明指向类的指针
- c++重新评估引用转发性能
- 右值引用转发错误