Visual Studio C++ 2015中的std::codecvt如何使用char16_t或char32_t?

36

这段代码在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);
}

现在使用VS2015,我得到了:

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)

1
https://connect.microsoft.com/VisualStudio/feedback/details/1403302/unresolved-external-when-using-codecvt-utf8 - Hans Passant
1
是的,我已经谷歌过了,有解决方案吗? - user3443139
你找到解决方案或解决方法了吗? - petke
4个回答

37

虽然是老问题,但供日后参考:这是Visual Studio 2015中已知的一个bug,在MSDN Social上的此帖子的最新帖子(2016年1月7日)中有解释。

针对您的示例,解决方法如下(我将您的方法实现为自由函数以简化操作):

#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;
}
希望这个问题能在未来版本中得到修复,否则需要优化#if条件。 更新:不,它在VS 2017中没有被修复。因此,我已将预处理器条件更新为>= 1900(最初是== 1900)。

7
微软开发人员采用这样的方法令人沮丧... 想象一下,如果你有大量代码需要以这种方式重写... - Danatela
2
那对我有效。相反的方向呢?如果我执行auto p = reinterpret_cast<const char *>(utf8_string.data());并转而使用convert.from_bytes(p),我会得到“不存在适当的用户定义转换,从std::basic_string<int16_t,std::char_traits<int16_t>,std::allocator<int16_t>>到std::u16string”。 - marc40000
在ANTLR修复程序中发现了一个类似的解决方案和它的反转。但由于两次转换,它并不是最优解:https://github.com/antlr/antlr4/commit/de6f04be0beebd17ea6232f554635c5262127aaa - Mohan Kumar
4
在VS 2019预览版中仍未修复。 - Mohan Kumar

9

定义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

2
VS2017:错误 C2491:不允许定义 dllimport 静态数据成员 'std::codecvt<char16_t,char,_Mbstatet> :: id'。 - Bogdan
2
确实,使用 /MD 编译无法通过编译,因为外部 DLL 无法知道或使用我们的定义。但是,使用 /MT 可以解决问题。所以这只是一个半吊子的解决方法 :-) - pascalx

8

这个在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

另一个可能的解决方法是使用wstring_convert的默认第二个模板参数(wchar_t)。这适用于“MS Visual Studio 2015更新3”。请注意,这不是平台无关的解决方案。仅适用于Windows。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接