Использование std:: sort() без префикса "std", а также без "использования пространства имен std;" успешно компилируется

Как sort() определяется в namespace std, он всегда должен использоваться как std::sort. Но следующий код компилируется правильно даже без std.

#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> nums = {4,3,1,7,2,0};
    sort(nums.begin(),nums.end());
}

ideone.com

Но этот код не работает.

#include <array>
#include <algorithm>

int main()
{

    std::array<int,5> nums = {4,1,8,9,6};
    sort(nums.begin(),nums.end());
}

Использование gcc 4.8.4 с флагом -std=c++11.

Из обоих этих фрагментов кода ясно, что std::vector имеет какое-то отношение к этому. Но я не могу понять это.

Ответ 1

Это зависимый от аргументов поиск. Если вы используете typeid для изучения типов задействованных итераторов:

#include <iostream>
#include <typeinfo>
#include <vector>
#include <array>

int main() {
    std::cout << typeid(std::vector<int>::iterator).name() << '\n';
    std::cout << typeid(std::array<int, 5>::iterator).name() << std::endl;
    return 0;
}

по крайней мере на Ideone, вы получите следующий результат:

N9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE
Pi

С помощью справки Revolver_Ocelot в комментариях мы видим, что эти типы __gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > > и int*.

Для вектора, после неудачного поиска обычного имени, компилятор ищет пространства имен __gnu_cxx и std для функции sort, __gnu_cxx, потому что это пространство имен __gnu_cxx::normal_iterator и std, потому что оно пространство имен одного из аргументов шаблона, std::vector<int, std::allocator<int> >. Он находит std::sort.

Для std::array итераторы - это всего лишь int* s, поэтому зависящий от аргументов поиск не ищет дополнительных пространств имен и не находит функцию sort.

Ответ 2

Это зависимый от аргумента поиск. Согласно Stroustroup Язык программирования С++: 4-е издание, здесь применяются два правила:

1) Если аргумент является членом пространства имен, соответствующие пространства имен являются охватывающими пространствами имен.

2) Если аргумент является встроенным типом, не существует связанных пространств имен.

В первом и втором случаях begin() и end() возвращают итераторы. Однако стандарт С++ определяет итератор как любую переменную любого типа, на которой может выполняться операция итерации. (Иными словами, итератор представляет собой концепцию дизайна, которая применяется через шаблон.)

В соответствии с другим ответом итераторы в первом случае являются переменными типа данных, которые принадлежат к тому же пространству имен, что и sort(). Однако итераторы во втором случае имеют примитивный тип данных. По правилу №2 эти итераторы не имеют связанного пространства имен.