Compilación de cadena y cadena de caracteres

7

Estoy creando una biblioteca. Quiero usarlo en múltiples proyectos que pueden usar multi-byte o unicode ( std::string o std::wstring ). He adoptado el antiguo método MS de compilación condicional:

namespace my_namespace {
#ifdef UNICODE
    typedef std::wstring String;
    typedef std::wstringstream StringStream;
    #define Str(s) L##s
#else
    typedef std::string String;
    typedef std::stringstream StringStream;
    #define Str(s) s
#endif
}

(La macro Str es para literales de cadena. VC ++ marca cadenas anchas con L . Ejemplo: L"this is a wide string"; )

¿Hay mejores maneras de lograr esto?

    
pregunta Johnny Mopp 22.07.2016 - 19:39

3 respuestas

1

La antigua técnica de Microsoft

La buena técnica antigua de Microsoft tiene Sirvió a millones de aplicaciones, por lo que definitivamente se considerará como un enfoque valioso y probado.

Tres comentarios:

  • Microsoft usa esta compilación condicional no solo para los pocos elementos centrales (TCHAR, TEXT, ...), sino también para muchas otras funciones relacionadas con cadenas (vea el ejemplo en el artículo de MSDN) para que esto trabajar consistentemente

  • Tienes que tener cuidado con la combinación de macros con espacios de nombres. Por ejemplo, Str() parece una función normal, pero es una macro definida globalmente y no se limita a su espacio de nombres (y se utiliza sin el prefijo de espacio de nombres). Sugeriría usar mayúsculas para hacer esto explícito

  • Si comienza ahora una nueva base de código, sugeriría adoptar la recomendación de Meyer de preferir el alias de tipo en lugar de typedef.

Variante menos redundante

Como en C ++ string / wstring , stringstream / wstringstream , etc ... son solo char / wchar_t especializaciones de basic_string<X> / basic_stringstream<X> , definiría tipos que se utilizarán en función del tipo de carácter subyacente que desee:

namespace mine {
#ifdef UNICODE
    using Char = wchar_t; 
    #define Str(s) L##s
#else
    using Char = char; 
    #define Str(s) s
#endif
    using String = std::basic_string<Char>;
    using StringStream = std::basic_stringstream<Char>;
    // ...  a lot more but only once
}

Demostración

Si es necesario, podría cambiar fácilmente a char32_t si quisiera trabajar con unicode de 32 bits en todas las plataformas (actualmente wchar_t en windows es de 16 bits y usa codificación UTF16, mientras que en linuts es de 32 bits y UTF32) como podría usar u32string ).

Compilación condicional

En teoría, podría imaginar una decisión en tiempo de ejecución si ejecutar Unicode o no. Pero para lograr esto, necesitaría crear todos los objetos usando una fábrica de resumen . Esto parece muy doloroso y complejo. No se habla del código hinchado teniendo cada función de cadena en doble.

Otro enfoque podría ser usar algunas plantillas para definir los tipos en tiempo de compilación usando alguna plantilla inteligente. Pero en última instancia, necesitaría confiar en alguna macro, que podría definir en sus scripts de compilación para automatizar la construcción de todas las versiones. Como al final confiarías en ellos, ¿por qué no facilitas el enfoque y los usas para lo que deben hacer?

    
respondido por el Christophe 25.08.2016 - 01:55
1

Por lo que vale, std::wstring no hace nada de lo que esperas (es UCS-2, no UTF-16, son diferentes; los primeros no pueden expresar caracteres fuera del plano multilingüe básico , incluyendo Emoji como U+1F44E THUMBS DOWN SIGN

respondido por el user238375 25.07.2016 - 21:28
0

En teoría, puedes usar el tipo de datos TCHAR, usar la versión 't' de todas las funciones de cadena y compilar con las definiciones adecuadas y todo funciona ...

.... pero en el mundo real, terminarás con algunas llamadas a la API que solo están disponibles en el formato incorrecto y que necesitan convertir cadenas entre codificaciones, y si no conoces la codificación de la página de códigos del mbcs cadena esto será problemático. (La suposición predeterminada es que está codificada en la página de códigos actual del SO, ¡pero es una suposición peligrosa debido a las redes!)

Otras cosas que van mal incluyen el código que asume que las cadenas wchar necesitan el mismo número de caracteres que las cadenas de caracteres y que la única conversión segura de Unicode a MCBS es especificar la página de códigos UTF8: caracteres Unicode que no existen en la página de códigos de destino se convierte en los caracteres "predeterminados", que es una excelente manera de perder sus caracteres asiáticos y árabes en un servidor de EE. UU.

Finalmente, recuerde que las letras Unicode pueden necesitar múltiples caracteres wchar para almacenar una sola letra,

    
respondido por el Michael Shaw 26.08.2016 - 22:05

Lea otras preguntas en las etiquetas