就常量性和引用性而言,函数应该如何接受 *lambda* 参数?
How should a function accept a *lambda* parameter, in terms of constness and referenceness?
以下各项的行为有何不同?
我不清楚 const
对函数参数有什么影响,以及在这种情况下按值传递、按引用传递或按右值引用传递之间的区别。
请注意,我了解按值传递和按引用传递之间的区别。但是,在 std::function 的特定情况下,或者更具体地说是 lambda,我不确定按值传递 lambda 与按引用传递 lambda 有什么区别。按值传递 lambda 意味着什么?将复制的数据是什么?
const
与 lambda 之间是否存在任何实际区别?
#include <functional>
void foo_with_func( std::function<void()> f) { ...; f(); ...; }
void foo_with_func( std::function<void()>& f) { ...; f(); ...; }
void foo_with_func( std::function<void()>&& f) { ...; f(); ...; }
void foo_with_func(const std::function<void()> f) { ...; f(); ...; }
void foo_with_func(const std::function<void()>& f) { ...; f(); ...; }
void foo_with_func(const std::function<void()>&& f) { ...; f(); ...; }
所有用法相同:
foo_with_func([&]() { ... });
经验法则:
常量参数
普通旧数据类型,例如 double, int,
和 char
应该按值传递(复制)。它们适合处理器寄存器,任何其他机制都可能需要更多的处理或内存。
较大的数据结构应该通过常量引用传递。将较大的结构复制到堆栈上会占用大量内存,并且需要额外的处理。传递引用意味着您引用的是现有项目。传递常量引用意味着该函数不会更改引用的项目。
可变参数
一个将被函数修改的参数应该通过引用传递。这允许您的程序修改项目 "in place"。
注意:我没有玩过移动语义,所以我不能推荐是否使用移动语义。
鉴于建议的用法 foo_with_func([&]() { ... });
,
void foo_with_func( std::function<void()>& f) { ...; f(); ...; }
将无法编译,因为它将非常量左值引用绑定到临时对象。其余的在任何体面的优化编译器中都是等效的。如果你还想用 std::function<void()> func;
调用它,那么通过传递 const 左值引用可能比按值传递更有效。
然而,其中 None 是最有效的,因为它们都会产生类型擦除成本。为了避免这些成本,编写一个模板并直接接受 lambda。
template<class F>
void foo_with_func(F f){ f(); }
如果 lambda 按值捕获并且复制成本很高,您也可以使用 F&&
。
以下各项的行为有何不同?
我不清楚 const
对函数参数有什么影响,以及在这种情况下按值传递、按引用传递或按右值引用传递之间的区别。
请注意,我了解按值传递和按引用传递之间的区别。但是,在 std::function 的特定情况下,或者更具体地说是 lambda,我不确定按值传递 lambda 与按引用传递 lambda 有什么区别。按值传递 lambda 意味着什么?将复制的数据是什么?
const
与 lambda 之间是否存在任何实际区别?
#include <functional>
void foo_with_func( std::function<void()> f) { ...; f(); ...; }
void foo_with_func( std::function<void()>& f) { ...; f(); ...; }
void foo_with_func( std::function<void()>&& f) { ...; f(); ...; }
void foo_with_func(const std::function<void()> f) { ...; f(); ...; }
void foo_with_func(const std::function<void()>& f) { ...; f(); ...; }
void foo_with_func(const std::function<void()>&& f) { ...; f(); ...; }
所有用法相同:
foo_with_func([&]() { ... });
经验法则:
常量参数
普通旧数据类型,例如 double, int,
和 char
应该按值传递(复制)。它们适合处理器寄存器,任何其他机制都可能需要更多的处理或内存。
较大的数据结构应该通过常量引用传递。将较大的结构复制到堆栈上会占用大量内存,并且需要额外的处理。传递引用意味着您引用的是现有项目。传递常量引用意味着该函数不会更改引用的项目。
可变参数
一个将被函数修改的参数应该通过引用传递。这允许您的程序修改项目 "in place"。
注意:我没有玩过移动语义,所以我不能推荐是否使用移动语义。
鉴于建议的用法 foo_with_func([&]() { ... });
,
void foo_with_func( std::function<void()>& f) { ...; f(); ...; }
将无法编译,因为它将非常量左值引用绑定到临时对象。其余的在任何体面的优化编译器中都是等效的。如果你还想用 std::function<void()> func;
调用它,那么通过传递 const 左值引用可能比按值传递更有效。
None 是最有效的,因为它们都会产生类型擦除成本。为了避免这些成本,编写一个模板并直接接受 lambda。
template<class F>
void foo_with_func(F f){ f(); }
如果 lambda 按值捕获并且复制成本很高,您也可以使用 F&&
。