2014-10-20 10 views
10

Ich nahm das folgende Beispiel aus http://en.cppreference.com/w/cpp/language/function_template#Function_template_overloading und Klirren (3.4) scheint es ganz gut, dass Handling, während g ++ (4.8.3) einen 'mehrdeutige Überlastung' Fehler gibt:Ist g ++ bei der Überladung von Funktionsvorlagen fehlerhaft?

struct A {}; 
template<class T> struct B { 
    template<class R> void operator*(R&){ cout << "1" << endl; }    // #1 
}; 
template<class T, class R> void operator*(T&, R&) { cout << "2" << endl;} // #2 
int main() { 
    A a; 
    B<A> b; 
    b * a; //prints 1 
} 

Klirren richtig drucken 1 (wie nach cppreference erwartet), während g ++ diesen Fehler gibt:

test_templates.cpp: In function ‘int main()’: 
test_templates.cpp:13:5: error: ambiguous overload for ‘operator*’ (operand types are ‘B<A>’ and ‘A’) 
    b * a; //prints 1 
    ^
test_templates.cpp:13:5: note: candidates are: 
test_templates.cpp:7:26: note: void B<T>::operator*(R&) [with R = A; T = A] 
    template<class R> void operator*(R&){ cout << "1" << endl; }   // #1 
         ^
test_templates.cpp:9:33: note: void operator*(T&, R&) [with T = B<A>; R = A] 
template<class T, class R> void operator*(T&, R&) { cout << "2" << endl;} // #2 

Ist g ++ misbehaving eigentlich hier?

+0

VS2012 (MSVC 11,0) berichten, dies auch als mehrdeutig – BeyelerStudios

+0

Well Klirren-3.4.2 in meiner Box auch berichtet, dies als eindeutig. 3.5 hat es zusammengestellt. Obwohl ich nicht sicher bin, ob es viel zu beantworten gibt. Die Verbindung ist ziemlich klar. Der Operator ist nicht eindeutig, aber er sollte mit einer Teilbestellung aufgelöst werden. Nur im Standard kann man entsprechende Zitate finden. Meine Wette ist, dass cppreference richtig ist. – luk32

+0

@ luk32 clang-3.4.2 kompiliert ok wenn '-std = C++ 11' /' -std = C++ 1y' –

Antwort

10

Dieses Beispiel stammt aus der standard (dies ist der Entwurf für C++ 11).

14.5.6.2 Teilbestellung von Funktionsschablonen Absatz 3 Beispiel:

struct A { }; 
template<class T> struct B { 
    template<class R> int operator*(R&); // #1 
}; 
template<class T, class R> int operator*(T&, R&); // #2 
// The declaration of B::operator* is transformed into the equivalent of 
// template<class R> int operator*(B<A>&, R&); // #1a 
int main() { 
    A a; 
    B<A> b; 
    b * a; // calls #1a 
} 

also der Standard selbst ziemlich viel sagen, das Gesetzbuch ist. Ich könnte Regeln kopieren, aber man könnte auch auf den Link klicken und zum entsprechenden Ort springen. Mein Punkt ist nur zu beweisen, dass dies ein ordnungsgemäß kompilierbarer Code ist, wie er durch den Standard definiert ist.

Für was es wert ist auf meinem debian clang 3.5.0 es sofort kompiliert hatte clang 3.4.2 mit -std=c++11, in allen Fällen g++ 4.9.1 berichtet Mehrdeutigkeit ausgeführt werden (I 1J sogar versucht).

Ich bin verwirrt von clang Verhalten, obwohl. Ich dachte, dass es in früheren Versionen von C++ mehrdeutig gewesen sein könnte, die Regel zur Disambiguierung wurde als Teil von C++ hinzugefügt, 11 und g++ hielten nicht Schritt. Aber clang 3.5 kompiliert es sogar mit -std=c++98.

+0

Sie schlagen mich um ein paar Sekunden, ich fand, dass in Standard, +1 btw – P0W

+0

@ P0W =) Nun, ich war interessiert, wenn Regeln die gleichen wie auf cppreference sind und bemerkte, es ist genau das gleiche Beispiel. Nicht meine stolzeste Antwort tbh, nur Copy-Pasterino, aber es beweist den Punkt g ++ ist falsch. – luk32

+0

Ist dies ein berichteter g ++ Bug? – ACyclic

0

Dieser Anruf ist ambiguos. GCC hat Recht.

§13.5.2/1
Thus, for any binary operator @, [email protected] can be interpas either [email protected](y) or [email protected](x,y). If both forms of the operator function have been declthe rules in 13.3.1.2 determine which, if any, interpretation is used.

Und in diesem Fall haben wir sowohl die Member-und Nicht-Member-Funktion. Die integrierte Version ist nicht enthalten, da der linke Operator den Klassentyp hat.

Wenn Sie den Operator explizit aufgerufen haben, gibt es keine Mehrdeutigkeit. Wenn der Aufruf jedoch über einen Operator erfolgt (also implizit) gibt es nichts, was zwischen Member und Nicht-Member unterscheiden kann, daher sind beide funktionsfähige Funktionen, die in diesem Fall zu einem mehrdeutigen Funktionsaufruf führen.

Frühere Versionen von Klirren Bericht als zweideutig auch: http://goo.gl/OWsJUv

+0

Ich denke, dass die Regeln für die Vorlage Fall und die Nicht-Vorlage Fall anders sind. Wie @ luk32 wies das Beispiel, das ich in meinem eingefügt Frage ist eigentlich aus dem Standard selbst. – dcmm88

+4

Es ist nicht wahr, dass es nichts gibt, was sie unterscheiden kann.Die Member-Funktion ist eine spezialisierte Vorlage wie in §14.5.6.2 erläutert – dcmm88

+0

@ dcmm88 Ich bin unsicher.Ihre Beobachtung ist technisch richtig aber warum wird nur 'clang 3.5.x' es dann kompilieren? Ich versuche, durch den Standard zu gehen, um herauszufinden. – edmz

Verwandte Themen