2012-03-15 18 views
6

Utilizzando Visual Studio 2010 SP1:Si tratta di un bug del compilatore VC++ 2010?

#include <vector> 

//namespace XXX { 
    struct Test 
    { 
    bool operator==(const Test& r) const { return true; } 
    }; 
//} 
//typedef XXX::Test Test; 

template <typename T> inline bool operator!=(const T& l,const T& r) 
{ return !(l==r); } 

int main() 
{ 
    std::vector<Test> vt; 
    std::vector<Test> vt2 = std::move(vt); 
    return 0; 
} 

Se compilo il codice di cui sopra come è, non riesce con questo errore:

1>C:\apps\MVS10\VC\include\vector(609): error C2593: 'operator !=' is ambiguous 
1>   C:\apps\MVS10\VC\include\xmemory(268): could be 'bool std::operator !=<_Ty,_Ty>(const std::allocator<_Ty> &,const std::allocator<_Ty> &) throw()' 
1>   with 
1>   [ 
1>    _Ty=Test 
1>   ] 
1>   test.cpp(11): or  'bool operator !=<std::allocator<_Ty>>(const T &,const T &)' [found using argument-dependent lookup] 
1>   with 
1>   [ 
1>    _Ty=Test, 
1>    T=std::allocator<Test> 
1>   ] 
1>   while trying to match the argument list '(std::allocator<_Ty>, std::allocator<_Ty>)' 
1>   with 
1>   [ 
1>    _Ty=Test 
1>   ] 
1>   C:\apps\MVS10\VC\include\vector(606) : while compiling class template member function 'void std::vector<_Ty>::_Assign_rv(std::vector<_Ty> &&)' 
1>   with 
1>   [ 
1>    _Ty=Test 
1>   ] 

... dove vector(609) risolve a questa linea:

 else if (get_allocator() != _Right.get_allocator()) 

OTOH, se rimedio alle righe correlate a namespace XXX, si compila senza reclami.

Devo pensare che questo sia un errore del compilatore ma sto cercando qualche verifica indipendente.

EDIT: Solo a titolo di spiegazione, mi sono imbattuto in questa situazione quando ho ricompilato il vecchio codice con VS2010 per la prima volta. L'operatore globale era un po 'cruft degli anni passati (ora rimosso). Non riuscivo a capire perché alcuni codici fallivano e altri no. Il codice sopra è la mia distillazione del caso fallito (ovviamente, il vecchio codice non conterrebbe le chiamate a std::move()).

UPDATE: mi sono collegato un bug con la SM e mi hanno risposto che questo è stato fissato "nella prossima versione del compilatore" - che presumo significa Visual C++ 11. Vedere: http://connect.microsoft.com/VisualStudio/feedback/details/731692/regression-involving-global-operator-and-std-vector

+0

Hai provato questo con un compilatore diverso? –

+0

@GregHewgill: non riesco a riprodurre con GCC. – mcmcc

+0

@GregHewgill: ho mentito nel mio precedente commento, non ho un altro compilatore a portata di mano che supporti C++ 11, quindi la risposta è no. – mcmcc

risposta

10

Si tratta di un bug .

Hai deciso di fornire operator!= per per tutti i tipi di che ovviamente causerà conflitti con tipi che hanno già definito un operatore del genere.

argomento di ricerca dipendente durante la risoluzione di una chiamata a operator!= tra due std::allocator<Test> s all'interno della vostra implementazione libreria [1] permette lo spazio dei nomi di Test da cercare (così come std) quando si cerca di trovare il operator!= da usare [2].

Quindi:

  • nel vostro caso rotto, che è namespace namespace globale, che contiene anche un operator!= che corrisponde. Ora, questo non dovrebbe importare, perché la funzione nel namespace std è una corrispondenza migliore [3]; il bug VS è che invece viene sollevata un'ambiguità.

  • ma quando Test è invece nello spazio dei nomi XXX (nonostante la typedef), lo spazio dei nomi cercato a causa della regola di cui sopra è invece lo spazio dei nomi XXX, che contiene alcuna definizione in conflitto per operator!=.

Meglio non definire operatori per tutti i tipi mai del genere, in ogni caso.


[1] Alcuni nell'ambito dell'attuazione per la vostra linea std::vector<Test> vt2 = std::move(vt); sulle tue impl compilatore/biblioteca invoca bool operator!=<std::allocator<Test>>(const std::allocator<Test>&, const std::allocator<Test>&).

[2] Citazioni seguono:

[C++11: 3.4.2/1]:When the postfix-expression in a function call (5.2.2) is an unqualified-id, other namespaces not considered during the usual unqualified lookup (3.4.1) may be searched, and in those namespaces, namespace-scope friend function declarations (11.3) not otherwise visible may be found. These modifications to the search depend on the types of the arguments (and for template template arguments, the namespace of the template argument).

[C++11: 3.4.2/2]:For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are determined in the following way:

  • [..]
  • If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces of which any template template arguments are members; and the classes of which any member templates used as template template arguments are members. [ Note: Non-type template arguments do not contribute to the set of associated namespaces. —end note ]
  • [..]

[3] Citazioni seguire:

[C++11: 13.3.3/1]: Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i , ICSi(F1) is not a worse conversion sequence than ICSi(F2) , and then:

  • [..]
  • F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.

[C++11: 14.5.6.2/2]: Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process.

La mia interpretazione è che questo processo determina che la funzione in std è " più specializzato "di quello nel namespace globale, quindi in effetti non dovrebbe esserci un'ambiguità.


Grazie @BoPersson e @ DavidRodríguez per il vostro prezioso contributo a questa risposta kick-ass.

+0

L'errore dice che il globale '! =' Specializzato per 'Test' è stato trovato a causa di ADL. Ciò che è discutibile è come la riga 606 contenga persino qualsiasi operando dal namespace globale, immagino. –

+0

@KerrekSB: Sì, è logico. Questo è uno dei suddetti "conflitti". –

+0

Dovrei aggiungere, ho provato tutte le combinazioni di typedef, overload dell'operatore, usando namespace ..., std :: rel_ops, ecc. Per trovare altre varianti di questo stesso errore. Questo è l'unico modo in cui potrei farlo fallire (in questo modo particolare). Sto avendo difficoltà a credere che non ci sia un bug del compilatore da qualche parte. – mcmcc

Problemi correlati