En mis máquinas Linux (y OS X), la iconv()función tiene este prototipo:
size_t iconv (iconv_t, char **inbuf...
mientras que en FreeBSD se ve así:
size_t iconv (iconv_t, const char **inbuf...
Me gustaría que mi código C ++ se construyera en ambas plataformas. Con los compiladores de C, pasar a char**para un const char**parámetro (o viceversa) normalmente emite una simple advertencia; sin embargo, en C ++ es un error fatal. Entonces, si paso a char**, no se compilará en BSD, y si paso a const char**, no se compilará en Linux / OS X. ¿Cómo puedo escribir código que se compile en ambos, sin tener que intentar detectar la plataforma?
Una idea (fallida) que tuve fue proporcionar un prototipo local que anule cualquiera proporcionado por el encabezado:
void myfunc(void) {
size_t iconv (iconv_t, char **inbuf);
iconv(foo, ptr);
}
Esto falla porque iconvnecesita un enlace C y no puede poner extern "C"dentro de una función (¿por qué no?)
La mejor idea de trabajo que se me ocurrió es lanzar el puntero de función en sí:
typedef void (*func_t)(iconv_t, const char **);
((func_t)(iconv))(foo, ptr);
pero esto tiene el potencial de enmascarar otros errores más graves.
fuente

iconvrequiereinbufque no sea constante.iconvsinconst: svnweb.freebsd.org/base/stable/9/include/…Respuestas:
Si lo que desea es hacer la vista gorda ante algunos problemas de constantes, puede utilizar una conversión que difumine la distinción, es decir, hace que char ** y const char ** sean interoperables:
Luego, más adelante en el programa:
sloppy () toma a
char**o aconst char*y lo convierte en achar**o aconst char*, lo que sea que exija el segundo parámetro de iconv.ACTUALIZACIÓN: cambiado para usar const_cast y llamar a descuidado no como cast.
fuente
sloppy<char**>()inicializador directamente allí.(char**)&inmenos que primero hagas un typedef parachar**.Puede eliminar la ambigüedad entre las dos declaraciones inspeccionando la firma de la función declarada. A continuación, se muestra un ejemplo básico de las plantillas necesarias para inspeccionar el tipo de parámetro. Esto podría generalizarse fácilmente (o podría usar los rasgos de función de Boost), pero esto es suficiente para demostrar una solución para su problema específico:
Aquí hay un ejemplo que demuestra el comportamiento:
Una vez que pueda detectar la calificación del tipo de parámetro, puede escribir dos funciones contenedoras que llaman
iconv: una que llamaiconvcon unchar const**argumento y otra que llamaiconvcon unchar**argumento.Debido a que debe evitarse la especialización de la plantilla de función, usamos una plantilla de clase para realizar la especialización. Tenga en cuenta que también hacemos de cada uno de los invocadores una plantilla de función, para asegurarnos de que solo se instancia la especialización que usamos. Si el compilador intenta generar código para la especialización incorrecta, obtendrá errores.
Luego ajustamos el uso de estos con un
call_iconvpara que llamar a esto sea tan simple como llamariconvdirectamente. El siguiente es un patrón general que muestra cómo se puede escribir esto:(Esta última lógica podría limpiarse y generalizarse; he intentado hacer que cada parte de ella sea explícita para, con suerte, dejar más claro cómo funciona).
fuente
decltyperequiere C ++ 11.#ifdefverificación de la plataforma, terminas con 30 líneas impares de código :) Sin embargo, un buen enfoque (aunque me he estado preocupando en los últimos días mirando preguntas sobre SO que las personas que no realmente entiendo lo que están haciendo han comenzado a usar SFINAE como un martillo de oro ... no es su caso, pero me temo que el código se volverá más complejo y difícil de mantener ...)Puede utilizar lo siguiente:
Puede pasar
const char**y en Linux / OSX pasará por la función de plantilla y en FreeBSD irá directamente aiconv.Inconveniente: permitirá llamadas como las
iconv(foo, 2.5)que pondrán al compilador en repetición infinita.fuente
const_castsería necesario moverlo a unadd_or_remove_constdispositivo que profundice en elT**para detectar si loTestáconsty agregar o eliminar la calificación según corresponda. Esto aún sería (mucho) más sencillo que la solución que he demostrado. Con un poco de trabajo, también podría ser posible hacer que esta solución funcione sin elconst_cast(es decir, usando una variable local en suiconv).iconvno sea constante, no seTdeduce comoconst char**, lo que significa que el parámetroinbuftiene tipoconst T, que esconst char **const, y la llamada aiconven la plantilla simplemente se llama a sí misma. Sin embargo, como dice James, con una modificación adecuada del tipo,Teste truco es la base de algo que funciona.Aquí tienes los identificadores de todos los sistemas operativos. Para mí no tiene ningún sentido intentar hacer algo que depende del sistema operativo sin verificar este sistema. Es como comprar unos pantalones verdes pero sin mirarlos.
fuente
without resorting to trying to detect the platform...Ha indicado que utilizar su propia función de contenedor es aceptable. También parece estar dispuesto a vivir con las advertencias.
Entonces, en lugar de escribir su contenedor en C ++, escríbalo en C, donde solo recibirá una advertencia en algunos sistemas:
fuente
Qué tal si
EDITAR: por supuesto, el "sin detectar la plataforma" es un problema. Vaya :-(
EDIT 2: ok, versión mejorada, ¿quizás?
fuente
const char**fallará)Qué pasa:
Creo que esto viola el alias estricto en C ++ 03, pero no en C ++ 11 porque en C ++ 11
const char**ychar**son los llamados "tipos similares". No va a evitar esa violación del aliasing estricto más que creando unconst char*, configúrelo igual a*foo, llameiconvcon un puntero al temporal y luego vuelva a copiar el resultado*foodespués de unconst_cast:Esto está a salvo del punto de vista de la corrección constante, porque todo lo que
iconvhaceinbufes incrementar el puntero almacenado en él. Así que estamos "desechando const" de un puntero derivado de un puntero que no era constante cuando lo vimos por primera vez.También podríamos escribir una sobrecarga de
myconvymyconv_helperque tomeconst char **inbufy altere las cosas en la otra dirección, de modo que la persona que llama tenga la opción de pasar aconst char**o achar**. Lo que podría decirse queiconvdebería haberle dado a la persona que llama en primer lugar en C ++, pero, por supuesto, la interfaz simplemente se copia de C donde no hay sobrecarga de funciones.fuente
Actualización: ahora veo que es posible manejarlo en C ++ sin autotools, pero dejo la solución de autoconf para las personas que la buscan.
Lo que está buscando es
iconv.m4cuál está instalado por el paquete gettext.AFAICS es solo:
en configure.ac, y debería detectar el prototipo correcto.
Luego, en el código que usa:
fuente
gettextpaquete. Además, es bastante común que los paquetes incluyan macros usadas en elm4/directorio y tenganACLOCAL_AMFLAGS = -I m4archivosMakefile.am. Creo que autopoint incluso lo copia en ese directorio de forma predeterminada.Llego tarde a esta fiesta pero aún así, aquí está mi solución:
fuente