23

次のプログラムswap()の呼び出しがあいまいなのはなぜですか?

#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の両方が発生します。std::swapが候補過負荷として考慮されている理由を私は理解していない

$ 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::allocator<T>fooの使用と関係があります。

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

答えて

17

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

[basic.lookup.argdep]/2、弾丸2、強調鉱山:Tクラステンプレートの特殊化である場合

さらに、その関連 名前空間およびクラスも含む:テンプレートのタイプに関連名前空間とクラス を テンプレートタイプパラメータ(テンプレートテンプレートパラメータを除く)に指定された引数。 テンプレートテンプレート引数がメンバである名前空間。 テンプレートテンプレートとして使用されているメンバテンプレートのクラスは、テンプレート引数 です。

...とポインタは、それらがポイント型などの関連名前空間/クラスの同じセットを有する:UへのポインタまたはUのアレイ、その関連する名前空間である

T場合と クラスはUに関連付けられたクラスです。

10

関連する名前空間のセットは、引数型から見えるさまざまな型に基づいて決定されます。特に、クラステンプレートの場合、関連する名前空間には、すべてのテンプレート引数の関連する名前空間が含まれます。引数依存ルックアップを使用して未修飾関数を検索すると、関連するすべての名前空間が検索されます。

foo<int>のテンプレート引数リストは、それによって画像に名前空間stdをドラッグし、実際にfoo<int, std::allocator<int>>あり、そこから入手swap()のための一般的な過負荷がすでに存在しています。

関連する問題