贡献者: addis
可调用类型(Callable)
最经典的是 C 语言的函数指针。C++ 还引入了函数引用,用法和指针类似(*
换成 &
即可)。
lambda 函数是 C++11 引入的。除了语法更简洁,好处主要在于可以修改函数的接口,预先填装一些参数或者改变参数的顺序或类型。例如一个积分函数 integral(T integrand, double start, doube end)
若要求 integrand
只接收一个 double
返回一个 double
,但我们想要积分的函数还需要其他若干参数。这时就可以直接 capture:auto integral = [¶m1, ¶m2](double x) { return fun1(param1, param2, x); }
。其中 &
是 capture by reference。也就是说 lambda 定义以后,仍然可以改变它们的值。不加 &
就是 capture by value,复制定义时的值。
[...]{...}
[&](...){...}
表示函数体所有用到的变量都是 capture by reference。[=]
是全部 by value。
m_data
,那么可以用 [this]
,[&this]
或者等效地,[&](...){...}
[=]
。这其中无论哪种,m_data
都不会真正被 copy。如果要 capture by value,那就直接 [m_data]
才可以。
sizeof()
通常是函数指针的函数,但如果有 capture,就会相应增加每个 capture 变量的 sizeof
。
const
,如果想改变可以用 [...](...) mutable {...}
但这不会影响被 capture 参数在函数外的值。capture by reference 的参数,在 lambda 函数中可以修改,修改后也会影响它在 lambda 外面的值。
[...](...) -> 类型 {...}
,此时返回值会试图 cast 成该类型。
auto
或者 auto &
。这样即使是同一个 lambda 对象,返回值的类型也可以由不同的输入值决定。相当于普通的函数模板声明返回 auto
。
functor 也可以达到 lambda 一样的效果。可以把 param1, param2
都用数据成员储存,在 operator()
中调用。但比起 lambda 还是略嫌麻烦。
static
变量。
用模板的一个坏处就是每种不同的参数都会生成一个额外的函数,会导致编译出的二进制文件体积增大(对非大型程序来说这一般不是问题)。在 C 语言中,函数传参问题的解决方法是把所有参数都用一个 void
指针打包,在函数体中再将其拆解并强制转换成所需的类型。
该方法的缺点就是如果不小心可能导致 type safety 相关问题,或者出现内存错误。