自定义::swap函数未被调用、代码无输出及std特化疑问排查
为什么我的自定义swap函数没被触发?
先来拆解你遇到的两个核心问题:
一、初始代码中两个swap都无输出的原因
首先看你贴的代码——你只定义了两个swap函数,但完全没有写调用它们的代码啊!比如你得加一句Test t1, t2; swap(t1, t2);(或者std::swap(t1, t2);)才会触发函数执行,不然编译器只会编译函数定义,不会主动调用它们,自然没输出。
退一步说,就算你加了调用语句,还有个const限定符的坑:你的两个swap参数都是const Test&,但如果你传递的是非const的Test对象(比如上面的t1、t2),编译器匹配的时候会优先选择不需要类型转换的候选。比如标准库默认的std::swap模板是template<class T> void swap(T&, T&),它接收非const引用,和你的非const对象完全匹配,而你的两个swap都需要把非const对象转成const引用,优先级更低,所以编译器会选默认的std::swap(而这个默认版本不会输出任何内容)。
二、移除const后,std特化被调用但全局swap没反应的原因
当你把std命名空间里的特化版本去掉const,变成:
namespace std { template<> void swap(Test& lhs, Test& rhs) { std::cout << "2"; } }
这时候如果你调用的是std::swap(t1, t2),编译器会优先匹配这个完全特化的模板版本——因为它比默认的通用模板更具体,所以会执行这个特化版本,输出"2"。
那为什么全局的swap(就算你也去掉了const)没被调用?这分两种情况:
- 如果你是直接写
std::swap(t1, t2):编译器只会在std命名空间里查找函数,根本不会去全局命名空间找,所以全局的swap完全没机会被选中。 - 如果你写的是
swap(t1, t2)(不带std::):这时候要看你有没有用using std::swap;。如果没有,编译器会通过ADL(依赖参数的查找)规则,因为Test是在全局命名空间定义的,所以只会找全局的swap,这时候全局版本会被调用;但如果你加了using std::swap;,那么全局swap和std的特化swap都是候选,这时候普通函数(全局swap)的优先级比模板特化更高,应该会调用全局版本——除非你没改全局swap的const,那全局版本还是const Test&参数,需要类型转换,优先级比std的特化版本低,所以还是会选std的。
总结一下,核心问题出在函数调用的方式和重载匹配的优先级上,还有最开始的“没写调用语句”这个小疏漏。
内容的提问来源于stack exchange,提问作者choxsword
相关产品推荐
相关产品推荐

