Странные правила перегрузки в C ++ - PullRequest
4 голосов
/ 28 мая 2010

Я пытаюсь скомпилировать этот код с GCC 4.5.0:

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

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

Это допустимый C ++?

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


Я провел несколько экспериментов, и мне кажется, я знаю, почему Comeau может скомпилировать это (но я не знаю это точно):

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.

1 Ответ

8 голосов
/ 28 мая 2010

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

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


Это допустимый C ++?

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

...