2013-07-06 26 views
19

B :: f neden belirsizliği çözmez, ancak A :: f yapar? dış kapsam bildirimleri gizler, ancak bağımsız ve bağımlı arama (ADL) bastırmak değildir:B :: f neden belirsizliği çözmez, ancak A :: f yapar?

namespace A 
{ 
    class X { }; 
    void f(X); 
} 

namespace B 
{ 
    void f(A::X); 
    void g(A::X x) 
    { 
     using B::f; // which expression shall I use here to select B::f? 
     f(x);   // ambiguous A::f or B::f 
    } 
} 

cevap

21

A izlenerek-bildirimi sıradan beyan olarak hareket eder. Eğer using B::f yaptığınızda

temelde hiçbir şey değiştirin. Yerel olarak, zaten zaten göründüğü yerde B::f'u yeniden işaretleyin. Bu, A::f ve B::f arasındaki belirsizliği yaratan ADL'nin A::f'u bulmasını engellemez.

using A::f yaparsanız, A::f yerel bildirimi, B::f dış bildirimini gizler. Bu nedenle B::f artık görünür değil ve artık nitelenmemiş ad aramasıyla bulunamadı. Artık sadece A::f bulundu, yani artık bir belirsizlik yok.

O ADL bastırmak mümkün değildir. Davanızdaki argüman türündedir,işlevi her zaman ADL tarafından f niteliksiz ad için bulunur. Bunu göz ardı edemezsin. Bu, belirsizlik yaratmadan B::f'u dikkate alamazsınız anlamına gelir. Etrafında tek yol nitelikli bir isim kullanmaktır. @Richard Smith gibi

doğru açıklamalarda belirtildiği, ADL bastırılabilir. ADL yalnızca işlev isminin kendisi işlev çağrısında postfix ifadesi olarak kullanıldığında kullanılır. Hedef işlevini başka bir şekilde belirtmek, ADL'yi bozar. Örneğin

, fonksiyon ibrenin başlatma çağrılır Yukarıdaki örnekte B::f olarak

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

ADL

tabi değildir. Ve işlev adının etrafında () bile sadece çifti

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

o B::f çağrı yapmak için zaten yeterlidir yani ADL bastırmak için yeterlidir.

+4

İşlev adını parantez içine alarak çağrı sitesinde ADL'yi kaldırabilirsiniz. '(F) (x)' yi kullanmak belirsizliği giderir. –

+0

Açıkçası, B :: f; 'kullanarak yukarıdaki kod alıntılarının hiçbirine gerek yoktur – Tony

1

Açıkça her seferinde ad alanı yazmalı. derleyici biz ad B içindedir çünkü B::f bulduğu ff(x) içinde çözmeye çalıştığında sadece

#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

evet: ...ve asla '' namespace xxx' kullanarak 'yapmak - sadece engelleri ve pis hatalar için yapar (' 'namespace std' kullanarak bile :) – slashmais

+0

@slashmais, tabii ki bu doğru. Ama böyle küçük bir parçada izin verildiğini düşünüyorum. En önemlisi buna alışmamaktır - eğer bunu yaparsanız gerçek kodda böyle yazmayı unutmayacaksınız. Ve evet - sabit! –

10

yok. Ayrıca x yana argument dependent lookup ad A tanımlanmıştır X bir örneğidir kullanılarak A::f bulur. Bu nedenle belirsizlik.

B::f numaralı bildirimin kullanımı, zaten B ad alanında bulunduğumuzdan beri bir etkisi yoktur.

, belirsizliği gidermek A::f(x) veya B::f(x) kullanın.