2013-02-26 21 views
9

Sono rimasto sorpreso dal fatto che GCC non non considerano la chiamata a foo() nel seguente programma ambiguo:chiamata Ovviamente ambigua non causa un errore di compilazione su 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); 
} 

La chiamata di funzione di cui sopra si compila e restituisce true su GCC 4.7.2 e GCC 4.8.0 (beta), mentre lo non compila (come mi aspetterei) su Clang 3.2 e ICC 13.0.1.

Si tratta di un caso di "diagnostica non necessaria" o è un bug in GCC? I riferimenti allo standard C++ 11 sono incoraggiati.

+0

Build fallito su VC11. Errore di chiamata ambiguo. –

+0

@MarkGarcia: Sì, sembra che solo GCC lo accetti.La domanda è se questo è dovuto a un errore o non è richiesta alcuna diagnostica per questo tipo di errore. –

+0

FWIW, g ++ 4.4.3 dà un errore, ma non quando si usa 'pippo' in' main', ma su 'using's in' C' già: 'ambig.cc:9: errore: usando la dichiarazione 'usando B2 :: pippo 'è in conflitto con una precedente dichiarazione using' – us2012

risposta

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.

Quindi, le dichiarazioni using sono legali, ma le funzioni sono colleghi nello stesso set di sovraccarico, come hai detto, e il programma è mal formato.

1

La chiamata a foo(true) nel programma è, come dici tu, chiaramente ambigua; inoltre, è ambiguo secondo l'algoritmo presentato in § 10.2 e, di conseguenza, dovrebbe essere contrassegnato per l'uso. (La segnalazione della dichiarazione using non è corretta, 10.2 (1) indica chiaramente che gli usi ambigui dei nomi sono segnalati alla ricerca, non alla dichiarazione.)

È interessante confrontare questo programma con uno simile, che è l'argomento di un a recognized gcc bug (leggermente modificato da tale segnalazione per rendere più chiaro il parallelo):

#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(); 
} 

il programma precedente è corretta; nonostante l'ereditarietà del diamante, foo è un membro statico di A, quindi non è ambiguo. In effetti, gcc lo compila senza problemi. Tuttavia, decommentando le due istanze di using A::foo, che non modifica nulla su foo, fa sì che gcc produca l'errore stranamente riduplicato annotato nella segnalazione di errore. Decommentando le due dichiarazioni using all'interno di C, che presumibilmente innesca l'altro bug che è l'oggetto di questa domanda, maschera l'errore static function e provoca la ricompilazione del programma.

clang sembra gestire tutte le possibili varianti di questo programma, per quello che vale.

Infine, ricordiamo che un dichiarato esplicitamente foo(bool) entro C (nel programma originale) vincerà su ogni foo(bool) portato in ambito C s' da using dichiarazioni. Sospetto che entrambi questi bug siano il risultato di una cattiva contabilità mentre si cerca di tenere traccia delle varie dichiarazioni di funzione nello scope di ciascuna classe e nella loro provenienza individuale (come una sequenza di dichiarazioni using e dichiarazioni di funzioni).