2013-02-26 13 views
9

ich durch die Tatsache überrascht, dass GCC tut nicht den Anruf zu foo() in dem folgende Programm betrachtet zweideutig:Offensichtlich mehrdeutig Anruf verursacht keine Kompilierungsfehler auf GCC

#include <iostream> 

struct B1 { bool foo(bool) { return true; } }; 
struct B2 { bool foo(bool) { return false; } }; 

struct C : public B1, public B2 
{ 
    using B1::foo; 
    using B2::foo; 
}; 

int main() 
{ 
    C c; 

    // Compiles and prints `true` on GCC 4.7.2 and GCC 4.8.0 (beta); 
    // does not compile on Clang 3.2 and ICC 13.0.1; 
    std::cout << std::boolalpha << c.foo(true); 
} 

Der obige Funktionsaufruf kompiliert und gibt true auf GCC 4.7.2 und GCC 4.8.0 (Beta) zurück, während es nicht kompiliert (wie ich erwarten würde) auf Clang 3.2 und ICC 13.0.1.

Ist dies ein Fall von "keine Diagnose erforderlich", oder ist es ein Fehler in GCC? Verweise auf den C++ 11-Standard werden empfohlen.

+0

Erstellung fehlgeschlagen auf VC11. Mehrdeutiger Aufruffehler. –

+0

@MarkGarcia: Ja, es scheint nur GCC akzeptiert es.Die Frage ist, ob dies auf einen Fehler zurückzuführen ist oder ob keine Diagnose für diese Art von Fehler erforderlich ist. –

+0

FWIW, g ++ 4.4.3 gibt einen Fehler, aber nicht, wenn 'foo' in' main' verwendet wird, aber auf 'using's in' C' bereits: 'ambig.cc:9: error: using declaration 'mit B2 :: foo 'steht in Konflikt mit einer vorherigen using-Deklaration – us2012

Antwort

4

§7.3.3/3:

In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined. If such a using-declaration names a constructor, the nested-name-specifier shall name a direct base class of the class being defined; otherwise it introduces the set of declarations found by member name lookup (10.2, 3.4.3.1).

¶14:

… [ Note: Two using-declarations may introduce functions with the same name and the same parameter types. If, for a call to an unqualified function name, function overload resolution selects the functions introduced by such using-declarations, the function call is ill-formed.

¶16:

For the purpose of overload resolution, the functions which are introduced by a using-declaration into a derived class will be treated as though they were members of the derived class.

Also, die using Erklärungen sind legal, doch die Funktionen Peers in der gleichen Überlastung gesetzt, wie Sie sagten, und das Programm ist schlecht gebildet.

1

Der Aufruf an foo(true) in Ihrem Programm ist, wie Sie sagen, eindeutig mehrdeutig; außerdem ist es gemäß dem Algorithmus, der in § 10.2 präsentiert wird, mehrdeutig und folglich sollte es bei Verwendung gekennzeichnet werden. (Die Kennzeichnung der using Deklaration wäre falsch; 10.2 (1) gibt eindeutig an, dass mehrdeutige Verwendungen von Namen beim Nachschlagen und nicht bei der Deklaration gekennzeichnet werden.)

Es ist interessant, dieses Programm mit einem ähnlichen Programm zu vergleichen, das Gegenstand von ein a recognized gcc bug (etwas von diesem Bug-Report modifiziert, um die parallel deutlicher zu machen):

#include <iostream> 

struct A { 
    static int foo() {return 1;} 
    static int foo(char) { return 2;} 
}; 

struct B1 : A { 
// using A::foo; 
}; 
struct B2 : A { 
// using A::foo; 
}; 

struct C : B1, B2 { 
// using B1::foo; 
// using B2::foo; 
}; 

int main() 
{ 
    std::cout << C::foo(); 
} 

Das obige Programm korrekt ist; Trotz der Diamantvererbung ist foo ein statisches Element von A, also ist es nicht mehrdeutig. In der Tat kompiliert gcc es ohne Probleme. Das Auskommentieren der beiden Instanzen von using A::foo, die nichts an foo ändert, bewirkt jedoch, dass gcc den im Fehlerbericht notierten merklich redundanten Fehler erzeugt. Wenn Sie die beiden using Deklarationen innerhalb C dekommentieren, was vermutlich den anderen Fehler auslöst, der Gegenstand dieser Frage ist, wird der Fehler static function maskiert und das Programm wird erneut kompiliert.

Clang scheint alle möglichen Varianten dieses Programms zu behandeln, für das, was es wert ist.

Schließlich ist zu beachten, dass eine explizit foo(bool) innerhalb C erklärt (im ursprünglichen Programm) wird jeder foo(bool) in C ‚s Umfang von using Erklärungen gebracht siegen über. Ich vermute, dass diese beiden Bugs das Ergebnis einer schlechten Buchführung sind, während sie versuchen, die verschiedenen Funktionsdeklarationen im Umfang jeder Klasse und ihre individuelle Herkunft zu verfolgen (als eine Folge von using Deklarationen und Funktionsdeklarationen).