为何对std::size_t类型参数使用非限定swap()时ADL未生效?
为何对std::size_t类型参数使用非限定swap()时ADL未生效?
这个问题其实戳中了ADL(实参依赖查找)的一个容易被忽略的细节——它的生效前提和实参的实际类型本质息息相关,我们一步步拆解来看:
先看能正常工作的std::vector案例
std::vector<int>是标准库在std命名空间下定义的类类型,当你调用非限定的swap(v1, v2)时,ADL的规则会触发:它会自动去实参类型所属的命名空间(也就是std)里查找swap函数。而标准库恰好为容器特化了std::swap,所以编译器能顺利找到并调用,这就是你看到的正常情况。
再看std::size_t的核心问题
你看到std::size_t写在std命名空间里,但它的本质只是一个内置基本类型的别名!比如在绝大多数编译器中,std::size_t其实是unsigned int或者unsigned long long的typedef——而这些底层的类型都是C++的内置基本类型,它们不属于任何命名空间(包括std)。
ADL有个关键限制:它只对**用户定义的类型(或其引用、指针)**生效,会去该类型的命名空间查找函数;但对于内置基本类型,ADL直接不会触发。所以哪怕你写的是std::size_t,编译器识别的实际类型是无所属命名空间的内置类型,自然不会去std命名空间找swap,而全局命名空间里又没有默认的swap实现,编译报错也就理所当然了。
给你个实用的小技巧
如果是在模板代码里想要兼顾ADL和内置类型的swap操作,业界有个常用的惯用法:
template<typename T> void safe_swap(T& a, T& b) { using std::swap; // 先把std::swap引入当前作用域作为备选 swap(a, b); // 优先尝试ADL查找,找不到就 fallback 到std::swap }
这样不管你的T是容器类(触发ADL用专属swap),还是像std::size_t这类内置类型别名(用std::swap),都能正常工作。
备注:内容来源于stack exchange,提问作者Kobi
相关产品推荐
相关产品推荐

