如何使用C++获取指定的重载函数地址
刚刚看到一篇博客,说 std::bind 无法绑定正确的重载函数。这里的问题并不是 std::bind 能力不足,而是将函数名传递给 std::bind 时编译器无法取到这个函数的地址(也就是符号,编译器会先解析成符号,链接器再替换为地址),因为有多个重载函数都是这个名字。核心问题是无法通过函数名取到想要的重载函数地址。就像下面的代码无法编译通过:
#includevoid f(){std::cout << "f 1" << std::endl; }void f(int x){std::cout << "f 2 " << x << std::endl; }int main(){auto p = &f; }
编译错误:
/home/abc/cpplearn/overload_func.cpp: In function ‘int main()’:有没有什么比较完美的解决办法呢?我觉得一定有,因为 C 语言没有函数重载,函数地址作为实参也是常规操作。相比之下,C++ 引入了函数重载,却无法取到函数地址,这就很尴尬。C++ 设计者肯定也想到了这个问题。
/home/abc/cpplearn/overload_func.cpp:15:15: error: unable to deduce ‘auto’ from ‘& f’
15 |auto p = &f;
|^
/home/abc/cpplearn/overload_func.cpp:15:15: note:couldn’t deduce template parameter ‘auto’
于是查阅了 cppreference.com,看到了 Address of an overloaded function。函数名的重载解析除了发生在函数调用的时候,也会发生在以下 7 种语境:
# | Context | Target |
---|---|---|
1 | initializer in a declaration of an object or reference | the object or reference being initialized |
2 | on the right-hand-side of an assignment expression | the left-hand side of the assignment |
3 | as a function call argument | the function parameter |
4 | as a user-defined operator argument | the operator parameter |
5 | the return statement |
the return type of a function |
6 | explicit cast or static_cast argument |
the target type of a cast |
7 | non-type template argument | the type of the template parameter |
先看第 3 种语境。当函数名作为函数调用的实参时,重载解析会选择和形参类型相匹配的版本。也就是说,下面的代码会如期运行:
#includevoid f(){std::cout << "f 1" << std::endl; }void f(int x){std::cout << "f 2 " << x << std::endl; }void call(void p(int)) {p(1); }int main(){call(f); }
这段代码输出:
f 2 1回到最初的问题,std::bind 也是函数,为什么无法正常编译呢?直接分析下面代码的编译错误信息:
#include#include void f(){std::cout << "f 1" << std::endl; }void f(int x){std::cout << "f 2 " << x << std::endl; }int main(){auto new_func = std::bind(f, std::placeholders::_1); new_func(66); }
编译错误:
/home/abc/cpplearn/overload_func.cpp: In function ‘int main()’:可以看到,std::bind 准确地说是一个函数模板。它要根据其参数进行模板实参推导,再替换模板形参进行实例化(Instantiation),产生和普通函数类似的汇编代码。std::bind 进行实例化的时候,函数
/home/abc/cpplearn/overload_func.cpp:16:30: error: no matching function for call to ‘bind(, const std::_Placeholder<1>&)’
16 |auto new_func = std::bind(f, std::placeholders::_1);
|~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
f
还没有进行重载解析,其类型为
。std::bind 无法进行实例化。怎样修改可以解决这个问题呢?可以利用第 6 个语境,也就是显示转换或 static_cast。重载解析会选择与它们的目标类型相匹配的版本。下面的代码会如期运行:
#include#include void f(){std::cout << "f 1" << std::endl; }void f(int x){std::cout << "f 2 " << x << std::endl; }int main(){auto new_func = std::bind((void(*)(int))f, std::placeholders::_1); new_func(66); }
这段代码输出:
f 2 66还有一种更加巧妙的办法,依然是利用第 3 种语境。既然 std::bind 的第一个模板实参的推导,和 f 的重载解析相矛盾。为什么不直接解决这个矛盾,将第一个模板实参改为显示指定?来看下面的代码:
#include#include void f(){std::cout << "f 1" << std::endl; }void f(int x){std::cout << "f 2 " << x << std::endl; }int main(){auto new_func = std::bind (f, std::placeholders::_1); new_func(66); }
这段代码如期输出:
f 2 66总结
【如何使用C++获取指定的重载函数地址】到此这篇关于如何使用C++获取指定的重载函数地址的文章就介绍到这了,更多相关C++获取重载函数地址内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- C/C++详解如何实现文件备份
- Android开发手册SeekBar拖动条使用实例
- RabbitMQ从概念到使用从Docker安装到RabbitMQ整合Springboot1.5w字最全教学
- Angular项目实战Angular2+如何去除URL中的#号
- RHEL 7 使用 CentOS 源安装 docker ce
- 数字孪生如何实现(有哪些潜力?)
- Android C++系列(Linux文件IO操作)
- Win10系统如何打造酷炫桌面效果?
- Win10系统如何设置腾讯游戏安全中心开机自打开?
- Win10系统硬盘空间如何自动清理?