Sort non qualifié () - pourquoi compile-t-il lorsqu'il est utilisé sur std :: vector et non sur std :: array, et quel compilateur est correct?


11

Lorsque vous faites appel 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 et clang renvoient tous deux une erreur sur le tri sur std::array- clang dit

erreur: utilisation de l'identifiant non déclaré «tri»; vouliez-vous dire 'std :: sort'?

Changer pour std::sort(begin(foo2), end(foo2))résoudre le problème.

MSVC compile le code ci-dessus tel qu'il est écrit.

Pourquoi la différence de traitement entre std::vectoret std::array; et quel compilateur est correct?


sort(...-> std::sort(.... Je suppose que l'ADL (recherche dépendante de l'argument) est ce qui vous fait trébucher. Ça, ou des guides de déduction. Dans tout les cas; qualifiez toujours les fonctions que vous appelez.
Jesper Juhl

3
Se pourrait-il que la bibliothèque MSVC ait une spécialisation std::sortqui mène à une recherche dépendante des arguments (comme vous l'avez déjà pour std::beginet std::end)?
Un programmeur mec le

1
@Someprogrammerdude C'est simplement que tous les conteneurs dans stdlib de VC ++ utilisent des itérateurs de type classe définis namespace stdmême là où un type de pointeur simple aurait fonctionné. Je crois que cela consiste à insérer des vérifications de build de débogage pour détecter les dépassements et autres erreurs courantes.
François Andrieux

Réponses:


16

Cela revient au type beginet au endrésultat et à la façon dont cela fonctionne avec la recherche dépendante de l'argument .

Dans

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

vous obtenez

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

et depuis std::vector<int>::iteratorest membre d' stdADL trouve sortdans stdet l'appel aboutit.

Avec

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

Vous obtenez

sort(int*, int*)

et parce qu'il int*n'est pas membre de std, ADL ne cherchera pas stdet vous ne trouverez pas std::sort.

Cela fonctionne dans MSVC car

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

devient

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

et puisque std::_Array_iteratorfait partie des stddécouvertes ADL sort.

Les deux compilateurs sont corrects avec ce comportement. std::vectoret std::arrayn'ont aucune exigence sur le type utilisé pour l'itérateur, sauf qu'il satisfait à l' exigence LegacyRandomAccessIterator et en C ++ 17 pour std::arrayque le type soit également un LiteralType et en C ++ 20 qu'il soit un ConstexprIterator


1
Je suppose que la question est de savoir si le comportement de MSVC est conforme, à savoir ce que le std::arrayiterator doivent être int*ou peut - il être un type de classe? De même, std::vectoril serait pertinent de se demander si l'itérateur doit être un type de classe sur lequel ADL fonctionnera, ou s'il peut l'être int*également.
noyer

@walnut Cela peut être ce que l'implémentation veut qu'il soit. Ce pourrait être un std::iterator, quelque chose d'autre, ou juste un pointeur.
NathanOliver

1
Je me demande également pourquoi dans cette implémentation de bibliothèque ils ont choisi d'utiliser int*pour std::arraymais pas pour std::vector.
François Andrieux

1
Les types d'itérateur pour les deux std::arrayet ne std::vectorsont pas spécifiés, ce qui signifie que l'implémentation est autorisée à les définir comme des pointeurs bruts (le code ne se compilera pas) ou des wrappers de type classe (le code se compilera uniquement si le type de classe a stdcomme espace de noms associé ADL).
aschepler

1
Voici une démo où l'ADL échoue avec un alias, et voici une démo où l'ADL réussit avec une classe imbriquée. Ici et dans mes tests précédents, std::vector<T>::iteratorest un alias.
user2357112 prend en charge Monica
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.