Некваліфікований sort () - чому він компілюється, коли використовується на std :: vector, а не на std :: array, і який компілятор є правильним?


11

При дзвінку std::sort()на std::array:

#include <vector>
#include <array>
#include <algorithm>

int main() {
    std::vector<int> foo{4, 1, 2, 3};
    sort(begin(foo), end(foo));

    std::array<int, 4> foo2{4, 1, 2, 3};
    sort(begin(foo2), end(foo2));
}

І gcc, і clang повертають помилку на сортування в std::array- clang

помилка: використання незадекларованого ідентифікатора 'сортування'; ви мали на увазі 'std :: sort'?

Зміна на std::sort(begin(foo2), end(foo2)) вирішити проблему.

MSVC компілює код вище, як написано.

Чому різниця в лікуванні між std::vectorта std::array; і який компілятор є правильним?


sort(...-> std::sort(.... Я думаю, що ADL (пошук, залежний від аргументів) - це те, що вас спонукає. Що, або дедуктивні настанови. У будь-якому випадку; завжди кваліфікуйте функції, які ви телефонуєте.
Jesper Juhl

3
Чи може бути, що бібліотека MSVC має певну спеціалізацію, std::sortщо призводить до пошуку аргументів, залежних від аргументів (як у вас уже є std::beginі для std::end)?
Якийсь програміст чувак

1
@Someprogrammerdude Просто всі контейнери в stdlib VC ++ використовують ітератори типу класу, визначені namespace stdнавіть там, де простий тип вказівника працював би. Я вважаю, що це вставити чеки налагодження налагодження, щоб виявити перевищення та інші поширені помилки.
Франсуа Андріо

Відповіді:


16

Це зводиться до того типу , який beginі endрезультат , щоб і як це працює з Аргумент' Dependent Lookup .

В

sort(begin(foo), end(foo));

Ви отримуєте

sort(std::vector<int>::iterator, std::vector<int>::iterator)

і оскільки std::vector<int>::iteratorє членом stdADL знахідок sortв stdі виклик завершується успішно.

З

sort(begin(foo2), end(foo2));

Ви отримуєте

sort(int*, int*)

а оскільки int*він не є членом std, ADL не загляне, stdі ви не можете його знайти std::sort.

Це працює в MSVC, оскільки

sort(begin(foo2), end(foo2));

стає

sort(std::_Array_iterator, std::_Array_iterator)

і оскільки std::_Array_iteratorє частиною stdзнахідок ADL sort.

Обидва компілятори правильно з такою поведінкою. std::vectorі std::arrayне має жодних вимог щодо того, який тип використовується для ітератора, за винятком того, що він задовольняє вимогам LegacyRandomAccessIterator, а в C ++ 17 - для std::arrayцього типу також буде LiteralType, а в C ++ 20 - це ConstexprIterator


1
Я думаю, питання полягає в тому, чи відповідає поведінка MSVC, тобто чи повинен бути std::arrayітератор чи це може бути тип класу? Аналогічно дляint*std::vector цього було б доречно питання, чи повинен ітератор бути класом типу, над яким працюватиме ADL, чи може це бути int*також.
волоський горіх

@walnut Це може бути все, що хоче реалізувати. Це може бути std::iteratorщось інше або просто вказівник.
NathanOliver

1
Я також ставлю собі питанням, чому в цій бібліотеці реалізації вони вирішили використовувати int*для std::arrayале не для std::vector.
Франсуа Андріо

1
Типи ітераторів для обох std::arrayі std::vectorне визначені, тобто реалізація дозволена визначати їх як необроблені покажчики (код не компілюється) або обгортки типу класу (код буде компілюватися лише у тому випадку, якщо тип класу має stdяк ADL, пов'язаний з простором імен).
асклеплер

1
Ось демонстрація, де ADL не працює з псевдонімом, і ось демонстрація де ADL досягає вкладеного класу. І тут, і в моїх попередніх тестах std::vector<T>::iterator- псевдонім.
user2357112 підтримує Моніку
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.