web-dev-qa-db-fra.com

Visual Studio C ++ 2015 std :: codecvt avec char16_t ou char32_t

Ce code compilé OK sous 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);
}

Maintenant avec VS2015 j'obtiens:

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)
32
user3443139

Ancienne question, mais pour référence future: il s'agit d'un bogue connu dans Visual Studio 2015, comme expliqué dans le dernier article (7 janvier 2016) dans ce fil de MSDN Social.

La solution de contournement pour votre exemple ressemble à ceci (j'ai implémenté votre méthode comme une fonction gratuite pour plus de simplicité):

#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;
}

Espérons que le problème sera résolu dans les prochaines versions, sinon le #if la condition devra être affinée. MISE À JOUR: non, non corrigé dans VS 2017. Par conséquent, j'ai mis à jour le préprocesseur conditionnel en >= 1900 (initialement était == 1900).

28
JPNotADragon

Définissez le symbole manquant dans un fichier 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
7
pascalx

Cela a fonctionné pour moi dans 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);
}
4
Paul Williams

Une autre solution de contournement possible consiste à utiliser le deuxième paramètre de modèle par défaut (wchar_t) pour wstring_convert. Il fonctionne pour "MS Visual Studio 2015 update 3". Veuillez noter qu'il s'agit d'une solution non indépendante de la plateforme. Windows seulement.

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);
}
3
aleksandrm8