我有两个用于ADL的片段用于演示目的.这两个片段都是由VC10编写的,gcc& comeau C编译器,结果对于这三个都是相同的.
#include <algorithm> namespace N { struct T {}; void swap(T,T) {} } namespace M { void swap(N::T,N::T) {} } int main() { using M::swap; N::T o1,o2; swap(o1,o2); }
编译结果:
error C2668: 'M::swap' : ambiguous call to overloaded function could be 'void M::swap(N::T,N::T)' or 'void N::swap(N::T,N::T)' [found using argument-dependent lookup]
这是预期的,因为ADL不优先于正常查找结果加上ADL不是二等公民,ADL搜索结果与正常(非ADL)无法定义查找联合.这就是为什么我们有歧义.
< 2> ADL反对使用std命名空间的指令:
#include <algorithm> namespace N { struct T {}; void swap(T,T) {} //point 1 } namespace M { void swap(N::T,N::T) {} } int main() { using std::swap; N::T o1,o2); }
这个编译好了.
结果是编译器选择ADL结果(它采用std :: swap的先例),意味着将调用’point 1’处的N :: swap().只有在缺少’第1点’时(比如我注释掉那一行),编译才会使用后退std :: swap代替.
注意这种方式已经在许多地方用作覆盖std :: swap的方法.
但我的问题是,为什么ADL优先于’std namespace'(case2)但被认为等于用户定义的命名空间函数(case1)?
C标准中有一段说明了吗?
================================================== ===============================
阅读有用的答案后编辑,可能对其他人有所帮助.
所以我调整了我的代码片段1&现在,模糊性已经消失,并且在进行重载分辨率时,编译显然更喜欢Nontemplate函数!
#include <algorithm> namespace N { struct T {}; void swap(T,T) {} } namespace M { template<class T> void swap(N::T,N::T) {} } int main() { using M::swap; N::T o1,o2); //here compiler choose N::swap() }
我也调整了我的片段2.只是为了让模糊看起来很有趣!
#include <algorithm> namespace N { struct T {}; template<class _Ty> inline void swap(_Ty& _Left,_Ty& _Right) { _Ty _Tmp = _Move(_Left); _Left = _Move(_Right); _Right = _Move(_Tmp); } } namespace M { void swap(N::T,o2); }
gcc和comeau都表达了预期的含糊不清:
"std::swap" matches the argument list,the choices that match are: function template "void N::swap(_Ty &,_Ty &)" function template "void std::swap(_Tp &,_Tp &)"
BTW VC10像往常一样愚蠢,让这个通过ok,除非我删除’using std :: swap’.
写一点:C重载可能很棘手(C标准中有30页),但在appendlix B上有一个非常易读的10页…
感谢所有不错的输入,现在很清楚.
解决方法
您的测试不会检查ADL是否优先于通常查找,而是检查重载决策如何确定最佳匹配.第二个测试用例的工作原因是std :: swap是一个模板,当对完美匹配(由ADL找到)和模板执行重载解析时,非模板化函数优先.