以下程序
#include#include #include namespace my_namespace { template void swap(T& a, T& b) { T tmp = std::move(a); a = std::move(b); b = std::move(tmp); } template > class foo {}; } int main() { my_namespace::foo *a, *b; using my_namespace::swap; swap(a,b); return 0; }
导致两者g++
并clang
在我的系统上发出以下编译器错误:
$ clang -std=c++11 swap_repro.cpp -I. swap_repro.cpp:28:3: error: call to 'swap' is ambiguous swap(a,b); ^~~~ /usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/bits/algorithmfwd.h:571:5: note: candidate function [with _Tp = my_namespace::foo> *] swap(_Tp&, _Tp&) ^ swap_repro.cpp:10:6: note: candidate function [with T = my_namespace::foo > *] void swap(T& a, T& b) ^ 1 error generated. $ g++ -std=c++11 swap_repro.cpp -I. swap_repro.cpp: In function ‘int main()’: swap_repro.cpp:28:11: error: call of overloaded ‘swap(my_namespace::foo *&, my_namespace::foo *&)’ is ambiguous swap(a,b); ^ swap_repro.cpp:28:11: note: candidates are: swap_repro.cpp:10:6: note: void my_namespace::swap(T&, T&) [with T = my_namespace::foo *] void swap(T& a, T& b) ^ In file included from /usr/include/c++/4.9/bits/stl_pair.h:59:0, from /usr/include/c++/4.9/utility:70, from /usr/include/c++/4.9/algorithm:60, from swap_repro.cpp:1: /usr/include/c++/4.9/bits/move.h:166:5: note: void std::swap(_Tp&, _Tp&) [with _Tp = my_namespace::foo *] swap(_Tp& __a, _Tp& __b) ^
我不明白为什么std::swap
被认为是候选人超载,但它与foo
使用它有关std::allocator
.
消除foo
第二个模板参数允许程序编译而不会出错.
因为std::allocator
用作模板类型参数,所以std
命名空间是ADL的关联命名空间.
[basic.lookup.argdep]/2,bullet 2,强调我的:
此外,如果
T
是类模板特化,则其关联的名称空间和类还包括:与模板类型参数(模板模板参数除外)提供的模板参数类型相关联的名称空间和类 ; 任何模板模板参数都是成员的名称空间; 以及用作模板模板参数的任何成员模板的类都是成员.
...和指针具有与它们指向的类型相同的关联命名空间/类集:
如果
T
是指向U
或数组的指针U
,则其关联的名称空间和类是与之关联的名称空间和类U
.
基于参数类型可见的各种类型确定关联命名空间的集合.值得注意的是,对于类模板,关联的命名空间包括所有模板参数的关联命名空间.当使用依赖于参数的查找查找非限定函数时,将搜索所有关联的命名空间.
模板参数列表foo
实际上是foo
,因此将命名空间std
拖入图片中,并且已经存在swap()
可用的一般过载.