已弃用的头文件<codecvt>的替代方案

95
背景介绍:我的任务需要将UTF-8 XML文件转换为UTF-16(当然要包含正确的头文件)。因此,我搜索了关于将UTF-8转换为UTF-16的常规方法,并发现应该使用<codecvt>中提供的模板。
但是现在,该模板已被弃用,我想知道有什么新的常见方法可以完成相同的任务?
(完全不介意使用Boost,但与此同时,我希望尽可能地接近标准库。)
4个回答

30

不用担心。

根据同一信息来源

这个库组件应该被退役到Annex D,与之并列, 直到有一个合适的替代品被标准化为止

因此,在新的标准化、更安全的版本推出之前,您仍然可以使用它。


25
很遗憾,那只是一厢情愿的想法。 C++17已经被弃用。建议使用专门的文本处理库来替代。如果在使用Visual Studio 2017时,将会发出弃用警告。 - IInspectable
11
请问您需要使用哪个专门的文本处理库呢? - camccar
2
希望如此,因为仅仅废弃某个东西而不提供替代方案实在太容易了。 - gast128
7
如果“标准”随意更改而没有提供合适的替代品,那么这些“标准”有何用处呢?也许这些“标准”并不是真正的标准。“标准”委员会难道不会考虑由于废弃而造成的人力浪费吗? - rxantos
@camccar ICU: https://icu.unicode.org/ - rahman
推荐使用这个包:https://github.com/nemtrif/utfcpp - vy32

29

std::codecvt模板来自于<locale>本身并未被弃用。对于UTF-8转换为UTF-16,仍然存在std::codecvt<char16_t, char, std::mbstate_t>专业化。

然而,由于std::wstring_convertstd::wbuffer_convert连同标准转换facet一起被弃用,因此没有任何简单的方法可以使用facet进行字符串转换。

所以,正如Bolas已经回答的那样:自己实现它(或者像往常一样使用第三方库),或者继续使用弃用的API。


11
根据P0618的说明,<codecvt>头文件中的所有内容都已过时。不仅是typedefs;整个std::codecvt也已过时。 - Nicol Bolas
4
这份提案似乎没有建议对 <locale> 头文件中定义 codecvt_base 和 codecvt 的 [locale.codecvt] 进行任何更改。然而,根据文件的描述,我发现 w{string,buffer}_convert 也已被弃用,而据我所知,它们是唯一使用 codecvt facet 的标准函数。因此,即使 codecvt 没有被弃用,也没有什么容易的方法来使用它们。您认为文档中省略 std::codecvt 是无意的吗? - eerorika
5
basic_filebuf 使用它。 - T.C.
1
{btsdaf} - Richard Smith
9
根据P0636R0,P0618R0已被应用于C++17标准,这意味着自该标准修订以来,这些弃用功能已生效。 - eerorika
显示剩余2条评论

16

由于没有人真正回答问题并提供可用的替代代码,这里有一个但它只适用于Windows:

#include <string>
#include <stdexcept>
#include <Windows.h>

std::wstring string_to_wide_string(const std::string& string)
{
    if (string.empty())
    {
        return L"";
    }

    const auto size_needed = MultiByteToWideChar(CP_UTF8, 0, &string.at(0), (int)string.size(), nullptr, 0);
    if (size_needed <= 0)
    {
        throw std::runtime_error("MultiByteToWideChar() failed: " + std::to_string(size_needed));
    }

    std::wstring result(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &string.at(0), (int)string.size(), &result.at(0), size_needed);
    return result;
}

std::string wide_string_to_string(const std::wstring& wide_string)
{
    if (wide_string.empty())
    {
        return "";
    }

    const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, &wide_string.at(0), (int)wide_string.size(), nullptr, 0, nullptr, nullptr);
    if (size_needed <= 0)
    {
        throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed));
    }

    std::string result(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wide_string.at(0), (int)wide_string.size(), &result.at(0), size_needed, nullptr, nullptr);
    return result;
}

8
新的方法是...你需要自己编写。或者只是依赖于已经过时的功能。希望标准委员会在有一个有效的替代方案之前不会真正删除codecvt。

但目前还没有这样的替代方案。


15
问题是:我需要最便携的方法来完成这个任务。当然,总会有像icu、iconv以及其他各种库之类的东西,但以前有一个相当直观的方法,只需要三行代码,现在变成了一团糟。 - login_not_failed
6
@login_not_failed并不是“曾经”的事情,因为它目前仍然存在,并且在一段时间内不会被移除。请注意,我的翻译尽可能保持了原文的意思和语气,同时也更加通俗易懂。 - Cubbi
2
我写了很长时间的C++,然后尝试了Rust,然后又回来继续做一些C++项目;我承认Rust要好得多。我不明白为什么他们废弃了这个功能却没有提供替代方案。 - UltimaWeapon
@UltimaWeapon:弃用并不意味着删除。即使您现在没有替代方案,也应该弃用您打算替换的不良API。这就是弃用的目的 - Nicol Bolas
https://github.com/nemtrif/utfcpp - vy32

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