23

次のプログラム

#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;
}

私のシステムでは、次のコンパイラ エラーが発生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<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)
     ^

std::swapがオーバーロードの候補と見なされている理由はわかりませんが、fooの の使用と関係がありstd::allocator<T>ます。

の 2 番目のテンプレート パラメーターを削除fooすると、プログラムをエラーなしでコンパイルできます。

4

2 に答える 2

19

std::allocator<T>はテンプレート型の引数として使用されるため、std名前空間は ADL に関連付けられた名前空間です。

[basic.lookup.argdep]/2、箇条書き 2、強調鉱山:

さらに、Tがクラス テンプレートの特殊化である場合、それに関連付けられた名前空間とクラスには次のものも含まれます。テンプレート テンプレート引数がメンバーである名前空間。テンプレート テンプレート引数として使用されるメンバー テンプレートがメンバーであるクラス。

...そして、ポインターには、それらが指す型と同じ関連する名前空間/クラスのセットがあります。

Tが へのポインタUまたは の配列である場合U、関連付けられた名前空間とクラスは に関連付けられたものになりUます。

于 2015-12-03T20:45:19.507 に答える