Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this call to swap() ambiguous?

Tags:

The following program

#include <algorithm> #include <utility> #include <memory>  namespace my_namespace {   template<class T> void swap(T& a, T& b) {   T tmp = std::move(a);   a = std::move(b);   b = std::move(tmp); }  template<class T, class Alloc = std::allocator<T>> class foo {};  }  int main() {   my_namespace::foo<int> *a, *b;    using my_namespace::swap;    swap(a,b);    return 0; } 

causes both g++ and clang to issue the following compiler error on my system:

$ 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<int, std::allocator<int> > *]     swap(_Tp&, _Tp&)     ^ swap_repro.cpp:10:6: note: candidate function [with T = my_namespace::foo<int, std::allocator<int> > *] 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<int>*&, my_namespace::foo<int>*&)’ 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<int>*]  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<int>*]      swap(_Tp& __a, _Tp& __b)      ^ 

I don't understand why std::swap is being considered as a candidate overload, but it has something to do with foo's use of std::allocator<T>.

Eliminating foo's second template parameter allows the program to compile without error.

like image 510
Jared Hoberock Avatar asked Dec 03 '15 20:12

Jared Hoberock


Video Answer


1 Answers

Because std::allocator<T> is used as a template type argument, the std namespace is an associated namespace for ADL.

[basic.lookup.argdep]/2, bullet 2, emphasis mine:

Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces of which any template template arguments are members; and the classes of which any member templates used as template template arguments are members.

...and pointers have the same set of associated namespaces/classes as the type they point to:

If T is a pointer to U or an array of U, its associated namespaces and classes are those associated with U.

like image 112
T.C. Avatar answered Nov 06 '22 02:11

T.C.