Sort () no calificado: ¿por qué se compila cuando se usa en std :: vector y no en std :: array, y qué compilador es correcto?

11

Al llamar std::sort()a un 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));
}

Tanto gcc como clang devuelven un error en el tipo en el std::array- dice clang

error: uso del identificador no declarado 'sort'; ¿quiso decir 'std :: sort'?

Cambiar para std::sort(begin(foo2), end(foo2))solucionar el problema.

MSVC compila el código anterior como está escrito.

¿Por qué la diferencia en el tratamiento entre std::vectory std::array; y que compilador es correcto?

Guy Middleton
fuente
sort(...-> std::sort(.... Yo supongo que la ADL (dependiente de búsqueda argumento) es lo que te tropezar. Eso, o guías de deducción. En todo caso; Siempre califique las funciones que llama.
Jesper Juhl
3
¿Podría ser que la biblioteca MSVC tenga alguna especialización std::sortque conduzca a una búsqueda dependiente de argumentos (como ya tiene para std::beginy std::end)?
Algún tipo programador el
1
@Someprogrammerdude Es simplemente que todos los contenedores en stdlib de VC ++ usan iteradores de tipo de clase definidos namespace stdincluso donde un tipo de puntero simple hubiera funcionado. Creo que esto es para insertar verificaciones de compilación de depuración para detectar desbordamientos y otros errores comunes.
François Andrieux

Respuestas:

16

Esto se reduce al tipo beginy endresultado y cómo funciona con la búsqueda dependiente de argumentos .

En

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

usted obtiene

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

y puesto que std::vector<int>::iteratores un miembro de los stdhallazgos de ADL sorten stdy la llamada se realiza correctamente.

Con

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

Usted obtiene

sort(int*, int*)

y porque int*no es miembro de stdADL, no investigará stdy no podrá encontrarlo std::sort.

Esto funciona en MSVC porque

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

se convierte

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

y como std::_Array_iteratores parte de stdADL encuentra sort.

Ambos compiladores son correctos con este comportamiento. std::vectory std::arrayno tiene ningún requisito sobre qué tipo se usa para el iterador, excepto que cumple con el requisito de LegacyRandomAccessIterator y en C ++ 17 para std::arrayese tipo también es LiteralType y en C ++ 20 que es ConstexprIterator

NathanOliver
fuente
1
Supongo que la pregunta es si el comportamiento de MSVC es conforme, es decir, ¿el std::arrayiterador tiene que ser int*o puede ser un tipo de clase? Del mismo modo std::vector, sería relevante para la pregunta de si el iterador tiene que ser un tipo de clase en el que funcionará ADL, o si también puede serlo int*.
nogal
@walnut Puede ser lo que la implementación quiera que sea. Podría ser un std::iterator, algo más, o simplemente un puntero.
NathanOliver
1
También me pregunto por qué en esta implementación de biblioteca eligieron usar int*para std::arraypero no para std::vector.
François Andrieux
1
Los tipos de iterador para ambos std::arrayy std::vectorno están especificados, lo que significa que la implementación puede definirlos como punteros sin formato (el código no se compilará) o envoltorios de tipo de clase (el código se compilará solo si el tipo de clase tiene stdun espacio de nombres asociado a ADL).
Aschepler
1
Aquí hay una demostración donde el ADL falla con un alias, y aquí hay una demostración donde el ADL tiene éxito con una clase anidada. Tanto aquí como en mis pruebas anteriores, std::vector<T>::iteratores un alias.
user2357112 es compatible con Monica el