c++ compiler-errors lowercase toupper tolower

c++ - ¿Por qué no se puede cumplir con éxito "transform(s.begin(), s.end(), s.begin(), tolower)"?



compiler-errors lowercase (5)

David ya identificó el problema, es decir, un conflicto entre:

  • <cctype> de int tolower(int c)
  • <locale> template <typename charT> charT tolower(charT c, locale const& loc)

Usar el primero es mucho más fácil, pero es un comportamiento indefinido (desafortunadamente) tan pronto como se trata de algo más que ascii inferior (0-127) en caracteres firmados. Por cierto, recomiendo definir char como unsigned.

La versión de la plantilla estaría bien, pero tendría que usar el bind para proporcionar el segundo parámetro, y está destinado a ser feo ...

Entonces, ¿puedo presentar la biblioteca Boost String Algorith m?

Y lo que es más importante: boost::to_lower :)

boost::to_lower(s);

La expresividad es deseable.

Dado el código:

#include <iostream> #include <cctype> #include <string> #include <algorithm> using namespace std; int main() { string s("ABCDEFGHIJKL"); transform(s.begin(),s.end(),s.begin(),tolower); cout<<s<<endl; }

Me sale el error

No hay función 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> > >, __gnu_cxx::__normal_iterator<char*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, <unresolved overloaded function type>)

¿Qué significa "tipo de función sobrecargada sin resolver" ?

Si sustituyo el tolower con una función que escribí, ya no se producen errores.


El problema probablemente se relaciona con múltiples sobrecargas de tolower y el compilador no puede seleccionar uno por ti. Puede intentar calificarlo para seleccionar una versión específica del mismo, o tal vez deba proporcionar un puntero de función para desambiguar. La función tolower puede estar presente (múltiples sobrecargas diferentes) en el encabezado <locale> , así como en <cctype> .

Tratar:

int (*tl)(int) = tolower; // Select that particular overload transform(s.begin(),s.end(),s.begin(),tl );

Esto se puede hacer en una sola línea con un reparto, pero probablemente sea más difícil de leer:

transform(s.begin(),s.end(),s.begin(),(int (*)(int))tolower );


Navegando por mi <ctype> desde gcc 4.2.1, veo esto:

// -*- C++ -*- forwarding header. // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 // Free Software Foundation, Inc.

...

#ifndef _GLIBCXX_CCTYPE #define _GLIBCXX_CCTYPE 1 #pragma GCC system_header #include <bits/c++config.h> #include <ctype.h> // Get rid of those macros defined in <ctype.h> in lieu of real functions. #undef isalnum #undef isalpha

...

#undef tolower #undef toupper _GLIBCXX_BEGIN_NAMESPACE(std) using ::isalnum; using ::isalpha;

...

using ::tolower; using ::toupper; _GLIBCXX_END_NAMESPACE #endif

Así que parece que tolower existe tanto en los espacios de nombres std (de <cctype> ) como de root (de <ctype.h> ). No estoy seguro de lo que hace la #pragma .


Trate de usar ::tolower . Esto solucionó el problema para mí.


Veamos una lista de opciones que comienzan con lo peor y avanzan hacia lo mejor. Los listaremos aquí y los discutiremos a continuación:

  1. transform(cbegin(s), cend(s), begin(s), ::tolower)
  2. transform(cbegin(s), cend(s), begin(s), static_cast<int(*)(int)>(tolower))
  3. transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); })

El código en su pregunta, transform(s.begin(), s.end(), s.begin(), tolower) producirá un error como:

No hay función coincidente para la llamada a la transform(std::basic_string<char>::iterator, std::basic_string<char>::iterator, std::basic_string<char>::iterator, <unresolved overloaded function type>)

La razón por la que estaba obteniendo un "tipo de función sobrecargada sin resolver" es que hay 2 tolower de tolower en el std nombres std :

  1. La biblioteca de locale define la template <typename T> T tolower(T, const locale&)
  2. La biblioteca cctype define int tolower(int)

1 es la solución ofrecida por davka . Aborda su error aprovechando el hecho de que la tolower locale no está definida en el espacio de nombres global.

Dependiendo de la situación de su locale , puede ser tolower consideración. Puede encontrar una comparación de los tolower s aquí: ¿Qué tolower en C ++?

Desafortunadamente, 1 depende de la cctype de tolower cctype en el espacio de nombres global. Veamos por qué ese puede no ser el caso:

Está utilizando correctamente #include <cctype> , ya que hacer #include <ctype.h> ha quedado en desuso en C ++: http://en.cppreference.com/w/cpp/header

Pero el estándar de C ++ establece en D.3 [depr.c.headers] 2 de las declaraciones en los encabezados:

No se especifica si estos nombres se declaran o se definen primero dentro del alcance del espacio de nombres (3.3.6) del espacio de nombres std y luego se inyectan en el alcance del espacio de nombres global mediante declaraciones de uso explícitas (7.3.3)

Por lo tanto, la única forma en que podemos garantizar que nuestro código es independiente de la implementación es usar un tolower de namespace std . 2 es la solución ofrecida por David Rodríguez - dribeas . Aprovecha el hecho de que static_cast puede:

Utilícese para desambiguar las sobrecargas de funciones realizando una conversión de función a puntero a un tipo específico

Antes de continuar, permítame comentar que si encuentra que int (*)(int) es un poco confuso, puede leer más sobre la sintaxis del puntero de función here .

Lamentablemente, hay otro problema con el argumento de entrada de tolower , si:

No se puede representar como char sin signo y no es igual a EOF, el comportamiento no está definido

Está utilizando una string que utiliza elementos de tipo: char . Los estados estándar de char específicamente 7.1.6.2 [dcl.type.simple] 3:

Se define por la implementación si los objetos de tipo char se representan como cantidades firmadas o no firmadas. El especificador signed obliga a los objetos char a ser firmados

Entonces, si la implementación define un char para que signifique un signed char entonces 1 y 2 darán como resultado un comportamiento indefinido para todos los caracteres correspondientes a números negativos. (Si se utiliza una codificación de caracteres ASCII, los caracteres correspondientes a los números negativos son ASCII extendido ).

El comportamiento indefinido se puede evitar convirtiendo la entrada en un unsigned char antes de pasarlo a tolower . 3 logra que el uso de un lambda que acepta un unsigned char por valor, luego lo pasa a una conversión implícita a int .

Para garantizar el comportamiento definido en todas las implementaciones compatibles, independientemente de la codificación de caracteres, deberá usar la transform(cbegin(s), cend(s), begin(s), [](const unsigned char i){ return tolower(i); }) o algo similar.