デモ用に ADL の 2 つのスニペットがあります。どちらのスニペットも VC10、gcc、comeau C++ コンパイラでコンパイルされており、結果は 3 つすべてで同じです。
<1>ユーザー定義の名前空間のディレクティブを使用することに対する ADL:
#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 が第 2 級市民ではないため、ADL 検索結果が通常の (非 ADL) 条件のないルックアップと結合されるためです。だからこそ、私たちはあいまいさを持っています。
<2> std 名前空間のディレクティブを使用することに対する ADL:
#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;
swap(o1,o2);
}
これは正常にコンパイルされます。
その結果、コンパイラは ADL の結果を選択します (std::swap よりも優先されます)。つまりN::swap()
、「ポイント 1」で呼び出されます。「ポイント 1」がない場合 (たとえば、その行をコメントアウトした場合) のみ、コンパイルはstd::swap
代わりにフォールバックを使用します。
この方法は、 を上書きする方法として多くの場所で使用されていることに注意してくださいstd::swap
。しかし、私の質問は、ADL が「std 名前空間」(case2) よりも優先されるのに、ユーザー定義の名前空間関数 (case1) と同等と見なされるのはなぜですか?
そう言っているC++標準の段落はありますか?
================================================== =============================== 有用な回答を読んだ後に編集すると、他の人に役立つかもしれません。
だから私はスニペット1を微調整しました&今ではあいまいさがなくなり、オーバーロードの解決を行うときに非テンプレート関数を明らかに優先してコンパイルします!
#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;
swap(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,N::T) {}
}
int main()
{
using std::swap;
N::T o1,o2;
swap(o1,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 &)"
ところで、いつものように愚かな VC10 は、「using std::swap」を削除しない限り、これを問題なく通過させます。
もう少し書く必要があります: C++ のオーバーロードはトリッキーになる可能性があります (C++ 標準では 30+ ページ) が、付録 B には非常に読みやすい 10 ページがあります...
すべての素晴らしい入力に感謝します。これで明確になりました。