sort libreria funcion cstdlib algorithms c++ algorithm stl

libreria - sort c++



std:: transform() y toupper(), sin funciĆ³n coincidente (2)

Problema

std::transform( s.begin(), s.end(), std::back_inserter(out), std::toupper );

función no coincidente para la llamada a '' transform(__gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>) ''

Este es un error engañoso; la parte interesante no es que no haya "ninguna función coincidente" para la llamada, sino por qué no hay una función coincidente.

El motivo es que está pasando una referencia de función de un " <unresolved overloaded function type> " como argumento, y GCC prefiere el error en la llamada en lugar de este fallo de resolución de sobrecarga.

Explicación

Primero, debe considerar cómo se hereda la biblioteca C en C ++. <ctype.h> tiene una función int toupper(int) .

C ++ hereda esto:

[n3290: 21.7/1]: tablas 74, 75, 76, 77, 78 y 79 describen los encabezados <cctype> , <cwctype> , <cstring> , <cwchar> , <cstdlib> (conversiones de caracteres) y <cuchar> , respectivamente.

[n3290: 21.7/2]: El contenido de estos encabezados será el mismo que los encabezados de la Biblioteca C Estándar <ctype.h> , <wctype.h> , <string.h> , <wchar.h> y <stdlib.h> y la cabecera C Unicode TR <uchar.h> , respectivamente [..]

[n3290: 17.6.1.2/6]: nombres que se definen como funciones en C se definirán como funciones en la biblioteca estándar de C ++.

Pero el uso de <ctype.h> está en desuso:

[n3290: C.3.1/1]: para compatibilidad con la biblioteca C estándar, la biblioteca estándar C ++ proporciona los encabezados 18 C (D.5), pero su uso está obsoleto en C ++.

Y la forma de acceder al toupper C es a través del encabezado de compatibilidad con versiones anteriores de C ++ <cctype> . Para dichos encabezados, el contenido se mueve o se copia (según su implementación) en el std nombres std :

[n3290: 17.6.1.2/4]: [..] En la biblioteca estándar de C ++, sin embargo, las declaraciones (excepto los nombres que se definen como macros en C) están dentro del alcance del espacio de nombres (3.3.6) del espacio de nombres estándar. No se especifica si estos nombres se declaran primero en el ámbito del espacio de nombres global y luego se inyectan en el espacio de nombres estándar mediante declaraciones de uso explícitas (7.3.3).

Pero la biblioteca de C ++ también introduce una nueva plantilla de función específica de la configuración regional en el encabezado <locale> , que también se llama toupper (por supuesto, en el espacio de nombres std ):

[n3290: 22.2]: [..] template <class charT> charT toupper(charT c, const locale& loc); [..]

Entonces, cuando usa std::toupper , hay dos sobrecargas para elegir. Como no le dijo a GCC qué función desea utilizar, no se puede resolver la sobrecarga y no se puede completar su llamada a std::transform .

Disparidad

Ahora, el OP de esa pregunta original no se encontró con este problema. Probablemente no tenía la versión local de std::toupper en el alcance, pero tampoco tenías #include <locale> tampoco.

Sin embargo:

[n3290: 17.6.5.2]: Un encabezado de C ++ puede incluir otros encabezados de C ++.

Entonces sucede que su <iostream> o su <algorithm> , o los encabezados que incluyen esos encabezados, o los encabezados que incluyen esos encabezados (etc.), llevan a la inclusión de <locale> en su implementación.

Solución

Hay dos soluciones a esto.

  1. Puede proporcionar una cláusula de conversión para obligar al puntero de función a hacer referencia a la sobrecarga que desea utilizar:

    std::transform( s.begin(), s.end(), std::back_inserter(out), (int (*)(int))std::toupper // specific overload requested );

  2. Puede eliminar la versión de la configuración regional del conjunto de sobrecarga utilizando explícitamente el toupper global:

    std::transform( s.begin(), s.end(), std::back_inserter(out), ::toupper // global scope );

    Sin embargo, recuerde que si esta función en <cctype> está disponible o no, no se especifica ( [17.6.1.2/4] ), y el uso de <ctype.h> está en desuso ( [C.3.1/1] ).

    Por lo tanto, esta no es la opción que yo recomendaría.

( Nota: desprecio la escritura de los corchetes angulares como si fueran parte de los nombres de los encabezados - son parte de la sintaxis de #include , no de los nombres de los encabezados - pero lo he hecho aquí para mantener la coherencia con las citas del FDIS; y, para ser honesto, es más claro ...)

Probé el código de esta pregunta C ++ std :: transform () y toupper () ..why ¿esto falla?

#include <iostream> #include <algorithm> int main() { std::string s="hello"; std::string out; std::transform(s.begin(), s.end(), std::back_inserter(out), std::toupper); std::cout << "hello in upper case: " << out << std::endl; }

En teoría, debería haber funcionado, ya que es uno de los ejemplos del libro de Josuttis, pero no compila http://ideone.com/aYnfv .

¿Por qué GCC se quejó?

no matching function for call to ‘transform( __gnu_cxx::__normal_iterator<char*, std::basic_string <char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string <char, std::char_traits<char>, std::allocator<char> > >, std::back_insert_iterator<std::basic_string <char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)’

¿Me estoy perdiendo de algo? ¿Es un problema relacionado con GCC?


Simplemente use ::toupper lugar de std::toupper . Es decir, toupper definido en el espacio de nombres global, en lugar del definido en el std nombres std .

std::transform(s.begin(), s.end(), std::back_inserter(out), ::toupper);

Su funcionamiento: http://ideone.com/XURh7

El motivo por el que su código no funciona: hay otra función sobrecargada en el espacio de nombres std que está causando problemas al resolver el nombre, porque el compilador no puede decidir a qué sobrecarga se refiere, cuando simplemente pasa std::toupper . Es por eso que el compilador está diciendo un unresolved overloaded function type en el mensaje de error, que indica la presencia de sobrecarga (s).

Así que para ayudar al compilador a resolver la sobrecarga correcta, debe lanzar std::toupper as

(int (*)(int))std::toupper

Es decir, lo siguiente funcionaría:

//see the last argument, how it is casted to appropriate type std::transform(s.begin(), s.end(), std::back_inserter(out),(int (*)(int))std::toupper);

Compruébelo usted mismo: http://ideone.com/8A6iV