2012-03-15 13 views
6

Korzystanie z Visual Studio 2010 SP1:Czy jest to błąd kompilatora 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; 
} 

Gdybym skompilować kod powyżej, jak jest, nie jest on z tego błędu:

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>   ] 

... gdzie vector(609) postanawia tej linii:

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

OTOH, jeśli odkomentuję linie powiązane z namespace XXX, kompiluje się bez skargi.

Muszę myśleć, że jest to błąd kompilatora, ale szukam niezależnej weryfikacji.

EDIT: Tylko tytułem wyjaśnienia, natknąłem tej sytuacji kiedy rekompilacji jakiś stary kod z VS2010 po raz pierwszy. Globalny operator był jakimś cruftem z lat minionych (teraz usunięty). Po prostu nie mogłem zrozumieć, dlaczego jakiś kod zawiódł, a inni nie. Powyższy kod jest moją destylacją nieudanego przypadku (oczywiście stary kod nie zawierał połączeń z numerem std::move()).

UPDATE: Zalogowałem błąd z MS i oni odpowiedzieli, że zostało to ustalone „w następnej wersji kompilatora” - co przypuszczam oznacza Visual C++ 11. zobacz: http://connect.microsoft.com/VisualStudio/feedback/details/731692/regression-involving-global-operator-and-std-vector

+0

Czy próbowałeś tego z innym kompilatorem? –

+0

@GregHewgill: Nie mogę się rozmnażać z GCC. – mcmcc

+0

@GregHewgill: Skłamałem w moim poprzednim komentarzu, nie mam innego kompilatora pod ręką, który obsługuje C++ 11, więc odpowiedź brzmi "nie". – mcmcc

Odpowiedz

10

to błąd .

Zdecydowałeś się dostarczyć operator!= dla wszystkich typów kiedykolwiek, co oczywiście spowoduje konflikty z typami, które już mają zdefiniowanego takiego operatora.

Argument Dependent odnośników podczas uchwałą wywołaniu operator!= między dwoma std::allocator<Test> s wewnątrz biblioteki realizacji [1] pozwala nazw z Test być przeszukiwane (jak również std), gdy próbuje znaleźć operator!= używać [2].

Więc:

  • w przypadku uszkodzonego, że przestrzeń nazw jest globalną przestrzeń nazw, która zawiera również operator!= który pasuje. Teraz nie powinno to mieć znaczenia, ponieważ funkcja w przestrzeni nazw std jest lepszym rozwiązaniem: [3]; Błąd VS polega na tym, że zamiast tego powstaje niejednoznaczność.

  • ale kiedy Test jest natomiast w przestrzeni nazw XXX (mimo typedef), przestrzeń nazw poszukiwanej w związku z powyższą regułą jest zamiast nazw XXX, który nie zawiera definicji operator!= konflikcie.

Lepiej nie definiują operatorów dla wszystkich typów kiedykolwiek tak, w każdym przypadku.


[1] Część realizacji dla linii std::vector<Test> vt2 = std::move(vt); na swoim IMPL kompilator/Biblioteki powołuje bool operator!=<std::allocator<Test>>(const std::allocator<Test>&, const std::allocator<Test>&).

[2] Cytowania następujące:

[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] Cytowania następujące:

[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.

My interpretacja jest, że proces ten określa, że ​​działają w std jest " bardziej wyspecjalizowany niż ten w globalnej przestrzeni nazw, tak więc w rzeczywistości nie powinno to być niejasności.


Dzięki @BoPersson i @ DavidRodríguez za cenne składek do tej kick-ass odpowiedź.

+0

Błąd mówi, że globalne '! =' Specjalizowane dla 'Test' zostało znalezione z powodu ADL. To, co jest wątpliwe, to fakt, że linia 606 zawiera nawet operandy z globalnej przestrzeni nazw. –

+0

@KerrekSB: Tak, to ma sens. To jeden z wyżej wymienionych "konfliktów". –

+0

Powinienem dodać, wypróbowałem wszystkie kombinacje typedefs, przeciążenie operatora, używanie przestrzeni nazw ..., std :: rel_ops, itp., Aby wymyślić inne odmiany tego samego błędu. To jedyny sposób, w jaki mogłem go zmarnować (w ten szczególny sposób). Trudno mi uwierzyć, że gdzieś tutaj nie ma błędu kompilatora. – mcmcc

Powiązane problemy