8

C++11std::wstring_convert非常*适合标准的 UTF-8 <-> UTF-16/UCS2/UCS4 转换。但是,当我尝试使用不是 from 的构面来实例化 wstring_convert 或 wbuffer_convert 时<codecvt>,它没有按预期工作:

// works as expected
std::wstring_convert<std::codecvt_utf8<wchar_t>> ucs4conv;

// Now, by analogy, I want to try this:
std::wstring_convert<std::codecvt<wchar_t, char, std::mbstate_t>> gbconv(
        new std::codecvt_byname<wchar_t, char, std::mbstate_t>("zh_CN.gb18030"));

Clang++ 错误提示“在 ~wstring_convert 中调用 codecvt<> 的受保护析构函数”

Visual Studio 允许它(尽管它缺少该语言环境,但这是另一回事),因为它的 wstring_convert 将 facet 指针的生命周期管理典当到它作为成员持有的语言环境对象,并且语言环境知道如何删除指向所有方面的指针。

Visual Studio 是对的而 libc++ 是错的吗?

*正如在 clang++-2.9/libc++-svn 和 Visual Studio 2010 EE SP1 中实现的那样,以下示例适用于两者,但不适用于 GCC,遗憾的是:https ://ideone.com/hywz6

4

1 回答 1

10

诚然,我对这个答案有偏见。但我将尝试通过引用 N3290(不幸的是不再公开)来支持我的主张。我也会提供一个解决方案。

分析:

wstring_convert[conversions.string]/p2 中的概要包括:

private:
  byte_string byte_err_string;  // exposition only
  wide_string wide_err_string;  // exposition only
  Codecvt *cvtptr;              // exposition only
  state_type cvtstate;          // exposition only
  size_t cvtcount;              // exposition only

“仅说明”意味着wstring_convert不必按此拼写按此顺序排列这些成员。但是“仅展示”成员用于描述各种成员的效果,并且这些规范具有约束力。

所以问题似乎变成了:

规格是~wstring_convert()什么?

这可以在同一部分 ([conversions.string]) 的 p17 中找到:

~wstring_convert();

效果:析构函数将删除cvtptr.

这对我来说意味着~Codecvt()必须是可访问的,因此 libc++ 遵循 C++11 规范。

我也同意这是皇家的痛苦。

解决方案:

让所有 C++98/03 方面都具有受保护的析构函数已被证明非常不方便。这是一个可以接受任何方面并为其提供公共析构函数的适配器:

template <class Facet>
class usable_facet
    : public Facet
{
public:
    template <class ...Args>
        usable_facet(Args&& ...args)
            : Facet(std::forward<Args>(args)...) {}
    ~usable_facet() {}
};

您现在可以在代码中使用这个通用适配器:

typedef usable_facet<std::codecvt<wchar_t, char, std::mbstate_t>> C;
std::wstring_convert<C> gbconv(new C("zh_CN.gb18030"));

希望这可以帮助。

于 2011-09-29T15:50:24.337 回答