为什么std::function绑定成员函数时可使用两种不同可调用类型?
struct Foo { Foo(int num) : num_(num) {} void print_add(int i) const { std::cout << num_+i << '\n'; } int num_; }; int main () { function<void(const Foo*, int)> func = &Foo::print_add; function<void(const Foo&, int)> func2 = &Foo::print_add; Foo f(1), f2(2); func(&f, 2); func2(f2, 3); return 0; }
问题解答
这一现象的核心是C++标准为std::function定义的**INVOKE调用协议**,专门兼容了成员函数调用时对象参数的多种传入形式。
- 你对非静态成员函数的调用规则认知是正确的:
Foo::print_add作为const成员函数,调用时确实需要隐式传入类型为const Foo*的this指针。 std::function包装可调用对象时,不会要求参数和可调用对象的原生参数完全硬匹配,只会判断参数是否满足INVOKE规则的合法调用要求。对于指向成员函数的指针,INVOKE规则允许第一个参数为以下任意一种类型:- 成员所属类的匹配指针:此时直接将该指针作为this参数传入成员函数,对应代码中
func的用法,func(&f, 2)等价于(&f)->print_add(2),完全符合语法要求。 - 成员所属类的匹配左值引用:此时编译器会自动取引用对应对象的地址作为this指针传入,对应代码中
func2的用法,func2(f2, 3)等价于(&f2)->print_add(3),不会出现类型不匹配的问题。 - 额外补充:
std::shared_ptr<Foo>、std::unique_ptr<Foo>这类智能指针也可以作为第一个参数传入,INVOKE规则会自动处理得到合法的this指针。
- 成员所属类的匹配指针:此时直接将该指针作为this参数传入成员函数,对应代码中
- 这种设计是
std::function的核心特性之一:抹平不同可调用对象的调用形式差异,对外提供统一的调用接口,上层使用者不需要关心底层封装的是普通函数、成员函数还是自定义仿函数,只要按std::function声明的签名传参即可。
内容的提问来源于stack exchange,提问作者codesavesworld
相关产品推荐
相关产品推荐

