@
p64381 其一,如果你用结构体,需要 malloc。那什么时候析构?在复杂的并发程序(比如 actor framework 里面),你必须依赖内存托管,因为这个函数的生命周期是框架负责的,而不是你程序员负责的。用 std::function,那么只要你绑定给它的参数有正确的垃圾回收和拷贝机制(比如正确的拷贝构造,或者智能指针比如 std::shared_ptr ),那么 std::function 就会遵循这套机制。
其二,std::function 可以借助 bind 在普通函数上绑定临时参数,比如从一个 (int,int,std::string) 特化一个 (int,int)。当然你可以说,我用结构体存参数啊?这不对,因为我的接受者只接受 (int,int),连结构体都不接受,你哪里传进去呢?你只能特例化一个 (int,int) 函数,想办法把 std::string 和这个特例化参数绑定…… 说实话我不太清楚该怎么用 C 做这件事情,除非你说服那个接受者重新写一个接受 (int,int,struct Context*) 的一套东西出来。
更进一步地,std::function 和 std::bind 的价值在于给所有 C++ 的用户,类库的撰写者、类库的使用者,提供了一个统一的抽象接口。它解耦了这两个角色,类库设计者只要关注 (int,int),而类库使用者不受 (int,int) 这个参数签名的限制。不要有附加的 struct,不许要处理垃圾回收。只要符合 std::function 这套接口的标准,管你是函数指针,是函数对象( struct + operator()),是对象的某个成员函数,是类的静态函数,还是通过 std::bind 诱导出的 partial function,又或是局部的 lambda,反正对于接受者都一样没区别。
新时代的 C++ 适合大型工程,乃至于开源世界各种风格迥异的类库,这是 C++ 这套的价值所在。这些都是石器时代的那套不能解决的问题。
- - - -
C 那套不是完全不好,比如 ABI 统一,一个二进制库永流传。C++ 这套在这方面是有缺陷的,C++ 的 ABI 被人长期诟病,std::function 跨编译器使用可能会出现各种问题。但是这套在开源世界里面其实不成问题,你完全可以用统一的编译器进行编译。反而是 C 那套,没有一套统一的兼容层解耦调用者和类库设计者,所以必须自己处理所有事情。类库就很难写了。
我只能说到这里了。我知道你说的 struct 那套,我也用过 C,而且好几年前还沉迷过,觉得 C++ 太臃肿,编译出来的程序太大,编译太慢,还是 C 好。但是后来用过 c#、用过 python、回头好好学了学 c++(真是太多东西了,编译器方面比如模板元编程,enable_if,再比如各种 boost 库),又用过 scala。用过这么多东西,我只能说 C 真的表达力比其他所有语言弱一大截。很多设计方法你必须借助高级特性才能写得出来,而且对于 C++ 而言新特性才出来不久,可能还不好写。这会迫使你转投比如 scala akka。不过学了这么多,可选择余地也大得多,我现在写个什么玩意儿,也能就着需求挑语言了。因为不同语言写同样的东西,顶层设计可能差异巨大,而这种巨大的差异也会带来巨大的工作量的区别。
你可能不知道我说的一些东西,包括 actor framework 之类的。如果有时间强烈推荐你去看看。目前成熟的 actor framework 我觉得非 scala akka 莫属。你学过之后绝对会在写并发程序方面有不一样的体会的,会得到弥足珍贵的思想的。