C++17中using namespace std触发boost指针转换ADL问题
问题原因解析
这个现象和C++标准迭代中ADL(参数依赖查找)的规则变化、编译器名字查找逻辑直接相关,不存在std和boost的特殊隐式关联,具体逻辑拆解如下:
- 先明确基础前提:
std命名空间从C++11开始就自带std::static_pointer_cast、std::dynamic_pointer_cast两个函数模板,是为std::shared_ptr设计的指针转换接口;boost库也在自己的boost命名空间下实现了同名、同功能的函数模板,服务于boost::shared_ptr类型。 - C17及更早标准存在明确的名字查找限制:如果调用函数时显式写了模板参数列表(比如代码里
static_pointer_cast<Animal>(dp)中的<Animal>),常规作用域查找(非ADL的逐层向上找名字的逻辑)必须先找到至少一个模板(类模板、函数模板、变量模板均可),否则编译器会直接判定名字无效,根本不会触发ADL流程。
在C17下注释掉using namespace std;时,常规查找从main函数作用域逐层向上到全局作用域,根本找不到任何叫static_pointer_cast/dynamic_pointer_cast的模板——boost的实现藏在boost命名空间里,常规查找不会主动遍历命名空间内部,因此直接触发编译错误,连ADL流程都没启动,自然找不到boost的对应函数。 - 加上
using namespace std;之后编译通过、且实际调用的是boost版本的逻辑非常清晰:- 这行语句把
std下的所有名字(包括std::static_pointer_cast这个函数模板)引入到了全局作用域,常规查找顺利找到了一个同名函数模板,满足了C++17下启动ADL的前置条件。 - ADL启动后,会根据传入参数
dp/ap1的类型boost::shared_ptr<T>,将boost加入关联命名空间搜索列表,把boost::static_pointer_cast/boost::dynamic_pointer_cast加入重载候选集。 - 重载决议阶段,boost版本的函数形参是
boost::shared_ptr类型,和传入的实参完全匹配;std版本的形参是std::shared_ptr类型,无法匹配boost::shared_ptr实参,因此最终选择调用boost的实现,和调试观测到的结果完全一致。
- 这行语句把
- C20下不需要加
using namespace std;就能正常编译,是因为C20通过P0846R0提案修改了上述名字查找规则:就算调用带显式模板参数的函数时常规查找没找到任何模板,也会正常触发ADL搜索关联命名空间。这时候编译器会直接通过ADL找到boost命名空间下的对应转换函数,不需要靠std里的同名模板满足查找前置条件。
简单总结:
using namespace std;在这里的作用根本不是让代码调用std的转换函数,只是把std里的同名模板拉到全局作用域,帮代码满足C++17下启动ADL的前置要求而已,最后重载选择的还是参数更匹配的boost版本实现。
内容的提问来源于stack exchange,提问作者3N4N
相关产品推荐
相关产品推荐

