Unqualified sort () - Warum wird es kompiliert, wenn es auf std :: vector und nicht auf std :: array verwendet wird, und welcher Compiler ist korrekt?

11

Beim Aufrufen std::sort()eines 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));
}

Sowohl gcc als auch clang geben einen Fehler bei der Sortierung auf dem std::array- clang zurück

Fehler: Verwendung des nicht deklarierten Bezeichners 'sort'; meinten Sie 'std :: sort'?

Ändern, um std::sort(begin(foo2), end(foo2))das Problem zu beheben.

MSVC kompiliert den obigen Code wie geschrieben.

Warum der Unterschied in der Behandlung zwischen std::vectorund std::array; und welcher compiler ist richtig?

Guy Middleton
quelle
sort(...-> std::sort(.... Ich denke, dass ADL (argumentabhängige Suche) Sie auslöst. Das oder Abzugsleitfäden. Auf jeden Fall; Qualifizieren Sie immer die Funktionen, die Sie aufrufen.
Jesper Juhl
3
Könnte es sein, dass die MSVC-Bibliothek eine Spezialisierung hat std::sort, die zu einer argumentabhängigen Suche führt (wie Sie es bereits für std::beginund getan haben std::end)?
Ein Programmierer
1
@Someprogrammerdude Es ist einfach so, dass alle Container in VC ++ 's stdlib Klassentyp-Iteratoren verwenden, die namespace stdselbst dort definiert sind , wo ein einfacher Zeigertyp funktioniert hätte. Ich glaube, dies ist das Einfügen von Debug-Build-Prüfungen, um Überschreitungen und andere häufige Fehler zu erkennen.
François Andrieux

Antworten:

16

Dies hängt von dem Typ beginund dem endErgebnis ab und davon, wie dies mit der argumentabhängigen Suche funktioniert .

Im

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

du erhältst

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

und da std::vector<int>::iteratorfindet sich ein Mitglied von stdADL sortin stdund der Aufruf ist erfolgreich.

Mit

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

Du erhältst

sort(int*, int*)

und weil int*kein Mitglied von ist std, wird ADL nicht untersuchen stdund Sie können nicht finden std::sort.

Dies funktioniert in MSVC, weil

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

wird

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

und da std::_Array_iteratorist ein Teil von stdADL-Funden sort.

Beide Compiler sind mit diesem Verhalten korrekt. std::vectorund std::arrayes gibt keine Anforderung, welcher Typ für den Iterator verwendet wird, außer dass er die LegacyRandomAccessIterator- Anforderung erfüllt, und in C ++ 17 ist std::arrayder Typ auch ein LiteralType und in C ++ 20 ein ConstexprIterator

NathanOliver
quelle
1
Ich denke , die Frage ist , ob MSVC Verhalten konform ist , also tut dem std::arrayIterator hat sein int*oder es kann ein Klassentyp sein? Ähnliches gilt für std::vectorwäre es auf die Frage relevant, ob der Iterator sein muss ein Klassentyp , auf dem ADL funktionieren wird, oder ob es sein kann , int*auch.
Walnuss
@walnut Es kann sein, was die Implementierung will. Es könnte ein std::iterator, etwas anderes oder nur ein Zeiger sein.
NathanOliver
1
Ich frage mich auch , warum in dieser Bibliothek Implementierung sie verwenden wählten int*für , std::arrayaber nicht für std::vector.
François Andrieux
1
Die Iteratortypen für beide std::arrayund std::vectornicht näher bezeichnet sind, ist die Umsetzung Sinn erlaubt , sie als roher Zeiger zu definieren (Code wird nicht kompiliert) oder Klasse-Typ - Wrapper (Code kompiliert nur dann , wenn der Klassentyp hat stdals ADL zugehörigen Namespace).
Aschepler
1
Hier ist eine Demo, bei der die ADL mit einem Alias ​​fehlschlägt, und hier ist eine Demo, bei der die ADL mit einer verschachtelten Klasse erfolgreich ist. Sowohl hier als auch in meinen früheren Tests std::vector<T>::iteratorist ein Alias.
user2357112 unterstützt Monica