2013-07-06 10 views

答えて

21

using宣言は、外部スコープ宣言を隠すが、引数依存ルックアップ(ADL)を抑制しない通常の宣言として機能します。

using B::fを実行すると、基本的に何も変更されません。あなたは単にB::fをローカルスコープで再宣言します。ローカルスコープには既に表示されています。 ADLがA::fを見つけることを妨げないので、A::fB::fのあいまいさが発生します。

using A::fを実行する場合、ローカル宣言A::fは、外側宣言B::fを非表示にします。したがって、B::fは表示されなくなり、修飾されていない名前検索によってもはや検出されません。 A::fのみが見つかりました。これはもはやあいまいさがないことを意味します。

ADLを抑制することはできません。あなたのケースの引数は A::Xタイプなので、 A::fという関数は、修飾されていない名前 fのADLによって常に検出されます。それを考慮から除外することはできません。つまり、あいまいさを生じることなく B::fを考慮に入れることはできません。唯一の方法は、修飾された名前を使用することです。

@リチャードスミスがコメントに正しく記載しているように、ADLを抑制することができます。 ADLは、関数呼び出しで関数名自体を後置式として使用する場合にのみ使用されます。それ以外の方法でターゲット関数を指定すると、ADLが呼び出されます。例えば

、関数ポインタの初期化はB::fが呼び出される上記の例ではADL

void g(A::X x) 
{ 
    void (*pf)(A::X) = &f; 
    pf(x); 
} 

を受けません。さらには、関数名の周り()の単なるペアがADLを抑制するのに十分である、すなわち

void g(A::X x) 
{ 
    (f)(x); 
} 

はすでにそれがB::fを呼び出す作るのに十分です。

+4

コールサイトでADLを抑制するには、関数名をカッコで囲みます。 '(f)(x)'を使うとあいまいさが修正されます。 –

+0

明らかに、上記のコード抜粋のどれでも 'B :: f;'を使う必要はありません – Tony

1

明示的に名前空間を書く必要があります。コンパイラは、我々は、名前空間Bにあるので、それはB::fを見つけff(x)で解決しようとするときだけ

#include <iostream> 

namespace A 
{ 
    class X { }; 
    void f(X) { 
     std::cout << "A"; 
    } 
} 

namespace B 
{ 
    void f(A::X) { 
     std::cout << "B"; 
    } 
    void g(A::X x) 
    { 
     // using B::f; 
     B::f(x);   
    } 
} 

int main() { 
    B::g(A::X()); // outputs B 
} 
+0

はい:...'namespace xxx'を使うことは決してありません。 - それはあいまいで、厄介なバグを作るだけです(' namespace std'を使っていなくても)。 – slashmais

+0

@slashmais、もちろんそうです。しかし、そのような小さなスニペットで私はそれが許されると思う。最も重要なことは、それに慣れるのではなく、実際のコードでこのように書くのを忘れることです。そしてはい - 修正! –

10

を行います。 xがの名前空間に定義されたXのインスタンスであるため、argument dependent lookupを使用してA::fが見つかりました。したがって、あいまいさ。

B::fを使用した宣言は、すでに名前空間Bに入っているため、効果がありません。

あいまいさを解決するには、A::f(x)またはB::f(x)を使用してください。