【问题标题】:Visual Studio C++ 2015 std::codecvt with char16_t or char32_t带有 char16_t 或 char32_t 的 Visual Studio C++ 2015 std::codecvt
【发布时间】:2015-11-10 09:12:09
【问题描述】:

这段代码在VS2013下编译OK:

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)

【问题讨论】:

标签: c++ stl visual-studio-2015 char16-t char32-t


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    另一个可能的解决方法是为 wstring_convert 使用默认的第二个模板参数 (wchar_t)。它适用于“MS Visual Studio 2015 update 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);
    }
    

    【讨论】:

      【解决方案3】:

      在 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: 错误 C2491: 'std::codecvt::id': 不允许定义 dllimport 静态数据成员
      • 确实不能用 /MD 编译,因为外部 DLL 无法知道/使用我们的定义。它确实适用于 /MT。所以这只是解决方法的一半:-)
      【解决方案4】:

      老问题,但供将来参考:这是 Visual Studio 2015 中的一个已知错误,如 MSDN Social 的 this thread 的最新帖子(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 中未修复。因此,我已将预处理器条件更新为 &gt;= 1900(最初是 == 1900)。

      【讨论】:

      • 嗯,M$ 开发人员的这种方法令人沮丧...想象一下,您有大量代码需要以这种方式重写...
      • 这对我有用。反方向呢?如果我执行 auto p = reinterpret_cast(utf8_string.data());和 convert.from_bytes(p) 相反,我得到“没有合适的用户定义转换从“std::basic_string,std::allocator>”到“std:: u16string"存在"
      • 找到了一个类似的解决方案,但它在 antlr 修复中是相反的。但由于两次转换不是最佳的:github.com/antlr/antlr4/commit/…
      • 在 VS 2019 Preview 中仍未修复。
      猜你喜欢
      • 2013-10-04
      • 1970-01-01
      • 2021-06-25
      • 2016-06-17
      • 1970-01-01
      • 2011-12-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多