Saltar al contenido

std::transform() y toupper(), sin función coincidente

este problema se puede abordar de variadas formas, por lo tanto te mostramos la que en nuestra opinión es la resolución más completa.

Solución:

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

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

Está funcionando: http://ideone.com/XURh7

Razón por la que su código no funciona: hay otra función sobrecargada toupper en el espacio de nombres std lo 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 dice unresolved overloaded function type en el mensaje de error, que indica la presencia de sobrecarga(s).

Entonces, para ayudar al compilador a resolver la sobrecarga correcta, debe lanzar std::toupper como

(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

Problema

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

no hay función coincidente para llamar a ‘transform(__gnu_cxx::__normal_iterator, std::allocator > >, __gnu_cxx::__normal_iterator, std::allocator > >, std::back_insert_iterator, std::allocator > >, )

Este es un error engañoso; la parte interesante no es que no haya “función de coincidencia” para la llamada, pero por qué no hay ninguna función coincidente.

los por qué es que estás pasando una referencia de función de un “” como argumento, y GCC prefiere el error en la llamada en lugar de esta falla de resolución de sobrecarga.


Explicación

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

C++ hereda esto:

[n3290: 21.7/1]: Las tablas 74, 75, 76, 77, 78 y 79 describen los encabezados
, , , ,
(conversiones de caracteres), y respectivamente.

[n3290: 21.7/2]: El contenido de estos encabezados será el mismo que el de los encabezados de la Biblioteca C estándar. , ,
, y y el encabezado C Unicode TR respectivamente [..]

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

pero usando es obsoleto:

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

Y la forma de acceder a la C toupper es a través del encabezado de compatibilidad con versiones anteriores de C++ . Para tales encabezados, los contenidos son ya sea movido o copiado (dependiendo de su implementación) en el std espacio de nombres:

[n3290: 17.6.1.2/4]: [..] Sin embargo, en la biblioteca estándar de C++, 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 dentro del alcance 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 presenta una nueva plantilla de función específica de la configuración regional en el encabezado eso es además llamado toupper (por supuesto, en el espacio de nombres std):

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

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


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, de nuevo, no lo hiciste #include ¡cualquiera!

Sin embargo:

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

Por lo que simplemente sucede que o bien tu o tu o encabezados que esos encabezados incluyen, o encabezados que esos los encabezados incluyen (etc.), conducen a la inclusión de sobre su implementación.


Solución

Hay dos soluciones para 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 local del conjunto de sobrecarga utilizando explícitamente el global toupper:

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

    Sin embargo, recuerde que ya sea que esta función en está disponible no está especificado ([17.6.1.2/4]), y utilizando es obsoleto ([C.3.1/1]).

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


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

Si sostienes alguna perplejidad o capacidad de aumentar nuestro división puedes ejecutar una apostilla y con mucho gusto lo leeremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *