2010-05-28 3 views
4

Я пытаюсь скомпилировать этот код с GCC 4.5.0:Странные правила перегрузочные в C++

#include <algorithm> 
#include <vector> 

template <typename T> void sort(T, T) {} 

int main() 
{ 
    std::vector<int> v; 
    sort(v.begin(), v.end()); 
} 

Но это не похоже на работу:

$ g++ -c nm.cpp 
nm.cpp: In function ‘int main()’: 
nm.cpp:9:28: error: call of overloaded ‘sort(std::vector<int>::iterator, std::vector<int>::iterator)’ is ambiguous 
nm.cpp:4:28: note: candidates are: void sort(T, T) [with T = __gnu_cxx::__normal_iterator<int*, std::vector<int> >] 
/usr/lib/gcc/i686-pc-linux-gnu/4.5.0/../../../../include/c++/4.5.0/bits/stl_algo.h:5199:69: note:     void std::sort(_RAIter, _RAIter) [with _RAIter = __gnu_cxx::__normal_iterator<int*, std::vector<int> >] 

Комео компилирует этот код без ошибки. (4.3.10.1 Beta2, строгий C++ 03, нет C++ 0x)

Действительно ли это C++?

Почему GCC даже рассматривает std::sort как допустимую перегрузку?


Я некоторые эксперименты, и я думаю, я знаю, почему Комео может транслируют это (но я не знаю, что это за факт):

namespace foo { 
typedef int* iterator_a; 
class  iterator_b {}; 
template <typename T> void bar(T) {} 
} 

template <typename T> void bar(T) {} 

int main() 
{ 
    bar(foo::iterator_a()); // this compiles 
    bar(foo::iterator_b()); // this doesn't 
} 

Мое предположение о том, что первый вызов разрешается до bar(int*), поэтому нет ADL и нет двусмысленности, а второй вызов разрешается до bar(foo::iterator_b) и тянет foo::bar (но я не уверен).

Таким образом, GCC, вероятно, использует что-то вроде iterator_b, в то время как Comeau использует iterator_a.

+0

Я считаю, что поведение Комо странное, это означает, что их 'итератор' не живет в пространстве имен' std' или мне что-то не хватает? –

+0

Я обновил ответ с помощью кода, с которым вы можете играть. – bucels

ответ

8

Вы можете явно указать свою функцию sort, полностью присвоив имя как ::sort.

Неоднозначная перегрузка обусловлена ​​argument dependent lookup. В стандарте C++ не указывается, как следует применять std::vector<*>::iterator. Авторы библиотеки gcc решили использовать шаблон (__gnu_cxx::__normal_iterator) с аргументом типа шаблона std::vector, который приносит пространство имен std в список связанных пространств имен.


Действительно ли это C++?

Да, но поведение обоих компиляторов также соответствует стандарту C++. ADL представляет огромную головную боль с этой точки зрения, и полные последствия не были поняты только после стандартизации.

Смежные вопросы