Visual Studio C++ 2015 std::codecvt con char16_t o char32_t

4 minutos de lectura

Este código se compiló correctamente en VS2013:

std::string Unicode::utf16_to_utf8(std::u16string utf16_string)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
    return convert.to_bytes(utf16_string);
}

Ahora con VS2015 obtengo:

1>unicode.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: static class std::locale::id std::codecvt<char16_t,char,struct _Mbstatet>::id" (__imp_?id@?$codecvt@_SDU_Mbstatet@@@std@@2V0locale@2@A)

avatar de usuario
JPNotADragon

Pregunta anterior, pero para referencia futura: este es un error conocido en Visual Studio 2015, como se explica en la última publicación (7 de enero de 2016) en este hilo de MSDN Social.

La solución para su ejemplo se ve así (implementé su método como una función gratuita para simplificar):

#include <codecvt>
#include <locale>
#include <string>
#include <iostream>

#if _MSC_VER >= 1900

std::string utf16_to_utf8(std::u16string utf16_string)
{
    std::wstring_convert<std::codecvt_utf8_utf16<int16_t>, int16_t> convert;
    auto p = reinterpret_cast<const int16_t *>(utf16_string.data());
    return convert.to_bytes(p, p + utf16_string.size());
}

#else

std::string utf16_to_utf8(std::u16string utf16_string)
{
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
    return convert.to_bytes(utf16_string);
}

#endif

int main()
{
    std::cout << utf16_to_utf8(u"Élémentaire, mon cher Watson!") << std::endl;

    return 0;
}

Con suerte, el problema se solucionará en versiones futuras; de lo contrario, el #if la condición necesitará refinación. ACTUALIZACIÓN: no, no se corrigió en VS 2017. Por lo tanto, actualicé el preprocesador condicional a >= 1900 (inicialmente fue == 1900).

  • Bueno, ese enfoque de los desarrolladores de M$ es deprimente… Imagina que tienes toneladas de código que necesitas reescribir de esa manera…

    – Danatela

    15 de junio de 2016 a las 10:56

  • Eso funcionó para mí. ¿Qué tal la dirección opuesta? Si hago un auto p = reinterpret_cast(utf8_string.data()); y convert.from_bytes(p) en su lugar, obtengo que “no hay una conversión adecuada definida por el usuario de” std::basic_string, std::allocator>” a “std:: u16string” existe”

    – marc40000

    2 de junio de 2018 a las 0:50


  • Encontré una solución similar y es inversa en una solución antlr. pero no óptimo debido a dos conversiones: github.com/antlr/antlr4/commit/…

    – Mohan Kumar

    31 de enero de 2019 a las 13:42

  • aún no se ha solucionado en VS 2019 Preview.

    – Mohan Kumar

    31 de enero de 2019 a las 13:42

avatar de usuario
pascual

Defina el símbolo que falta en un archivo cpp.

// Apparently Microsoft forgot to define a symbol for codecvt.
// Works with /MT only
#include <locale>

#if (!_DLL) && (_MSC_VER >= 1900 /* VS 2015*/) && (_MSC_VER <= 1911 /* VS 2017 */)
std::locale::id std::codecvt<char16_t, char, _Mbstatet>::id;
#endif

  • VS2017: error C2491: ‘std::codecvt::id’: no ​​se permite la definición del miembro de datos estáticos dllimport

    – Bogdán

    27/09/2017 a las 20:51

  • De hecho, no se compila con /MARYLAND, porque la DLL extranjera no tendría forma de conocer/usar nuestra definición. Funciona con /MONTE aunque. Así que es solo la mitad de una solución alternativa 🙂

    – pascual

    27/09/2017 a las 22:10

Esto funcionó para mí en VS2017:

std::wstring utf8_to_utf16(std::string utf8_string)
{
   return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>{}.from_bytes(utf8_string);
}

std::string utf16_to_utf8(std::wstring utf16_string)
{
    return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>{}.to_bytes(utf16_string);
}

Otra posible solución es usar el segundo parámetro de plantilla predeterminado (wchar_t) para wstring_convert. Está funcionando para “MS Visual Studio 2015 actualización 3”. Tenga en cuenta que es no independiente de la plataforma solución. Solo ventanas.

std::string utf16_to_utf8(std::u16string u16_string)
{
    std::wstring wide_string(u16_string.begin(), u16_string.end());
    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
    return convert.to_bytes(wide_string);
}

¿Ha sido útil esta solución?