2013-01-16 12 views
12

Czy to jest błąd kompilatora?Operator w zakresie przestrzeni nazw ukrywający inny w zakresie globalnym

template <typename T> 
T& operator++(T& t) 
{ 
    return t; 
} 

namespace asdf { 

enum Foo { }; 
enum Bar { }; 

Foo& operator++(Foo& foo); 

void fun() 
{ 
    Bar bar; 
    ++bar; 
} 

} // end namespace asdf 

int main() 
{ 
    return 0; 
} 

Komunikat o błędzie GCC 4.7 jest:

error: no match for 'operator++' in '++bar' 
note: candidate is: 
note: asdf::Foo& asdf::operator++(asdf::Foo&) 
note: no known conversion for argument 1 from 'asdf::Bar' to 'asdf::Foo&' 

To kompiluje jeśli skomentuj linię:

Foo& operator++(Foo& foo); 
+1

[Tak jest] (http://liveworkspace.org/code/2vreOi$0) .... –

+3

Nie sądzę. VC++ generuje to samo. – SChepurin

+1

@KarthikT: Nie jestem pewien, w jaki sposób połączony kod obsługuje "argument o błędzie". –

Odpowiedz

13

Nie, to nie jest błąd. Rozważa się trzy równoległe zestawy operatorów. Członkowie, operatorzy nie będący członkami i wbudowani.

Te nieczłonkowskie są wyszukiwane przez normalne niewykwalifikowane + wyszukiwanie ADL, ignorując wszystkie funkcje członków klasy. Stąd globalny operator jest ukryty przez leksykalny, bliższy (a interweniująca funkcja członka nie ukryłaby innych nie-członków).

Należy zauważyć, że rozdzielczość przeciążania ma miejsce po wyszukiwanie nazwy ; w twoim przypadku znaleziono nazwę operator++, ale nie ma odpowiedniego przeciążenia.

Jeżeli Bar został uznany na całym świecie, i/lub drugiego operatora w przestrzeni nazw asdf, ADL (w pierwszym przypadku) lub zwykły niewykwalifikowany odnośnika (w tym ostatnim przypadku) byłby przeciągnięty operatorowi.


: Overload resolution (...) takes place after name lookup has succeeded. (C++ standard)

+0

Nie jestem pewien, czy to wystarczająco dużo szczegółów. W przypadku niezgodności, czy nie należy szukać następnej otaczającej przestrzeni nazw? –

+1

@phresnel: Ale w jaki sposób nazwa 'operator ++' tworzy niezgodną dla 'operatora ++'? Jest to tylko * nazwa *, która jest istotna podczas sprawdzania nazwy. –

+0

@phresnel, faktycznie lokalne deklaracje są również uważane. zaktualizuje ... –

7

nie, to nie jest błąd kompilatora.

Istnieją dwa wyszukiwania nazw, które zostaną wykonane dla wyrażenia ++bar.

  • Regularne wyszukiwanie nazw przeszukuje otaczających zasięgów i nazw aż znajdzie pierwszy wystąpienie operator++. To wyszukiwanie działa od wewnątrz, więc globalna przestrzeń nazw jest wyszukiwana jako ostatnia. Szukając funkcji operatora, funkcje składowe są traktowane osobno (i nie przerywaj tego wyszukiwania).
  • Wyszukiwanie zależne od argumentu kopie w następnej kolejności i przeszukuje dodatkowe klasy i przestrzenie nazw, ale tylko te, które są powiązane z argumentami funkcji (w tym przypadku jest to operator++).

W przykładzie w pytaniu normalne wyszukiwanie znajduje asdf::operator++ i przestaje wyglądać.
Wyszukiwanie zależne od argumentów dodaje tylko obszar nazw asdf do miejsc do wyszukiwania, ponieważ jest to powiązany obszar nazw dla enum Bar. Z tego powodu nie można znaleźć globalnego operator++.

Można wprowadzić globalny kod operator++ przy użyciu deklaracji użycia w przestrzeni nazw asdf.

+0

Pierwszy opisany punkt nie dotyczy zakresów klas. to znaczy, nawet jeśli w funkcji członkowskiej klasy używasz wyrażenia operatora, operator zakresu obszaru nazw, nawet w zakresie przestrzeni nazw pokrewnym nonadl, można znaleźć pomimo istnienia operatora członkowskiego o tej samej nazwie. –

+0

@ JohannesSchaub-litb: Czy jest to zmiana między C++ 03 i C++ 11? Ponieważ nie mogę znaleźć takiego wyjątku w C++ 03, klauzula 3.4.1 [basic.lookup.unqual]. –

+1

zasady są określone w 13.3.1.2 :-) –

1

Przeciążenie dotyczy tylko nazw zdefiniowanych w tym samym zakresie. Po znalezieniu przez kompilator pasującej nazwy nie wygląda on w zewnętrznych zakresach, nawet jeśli znaleziona nazwa dotyczy czegoś, czego nie można użyć. Nie ma to nic wspólnego z operatorami; jeśli kod użyłby nazwy funkcji w taki sam sposób, w jaki używa operatora ++, otrzyma ten sam błąd.Na przykład:

void f(int); 

struct C { 
void f(const C&); 
void g() { 
    f(3); // error: f(const C&) can't be called with argument 3 
}; 
Powiązane problemy