libc ++ против VC ++: можно ли преобразовать не в UTF с помощью wstring_convert? - PullRequest
8 голосов
/ 29 сентября 2011

C ++ 11 std::wstring_convert прекрасно работает * для стандартных преобразований UTF-8 <-> UTF-16 / UCS2 / UCS4. Однако когда я попытался создать экземпляр 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 ++ выдает ошибку, говоря "вызов защищенного деструктора codecvt <> в ~ wstring_convert"

Visual Studio позволяет это (хотя в ней отсутствует эта локаль, но это уже другая история), поскольку ее wstring_convert обеспечивает управление временем жизни указателя фасета для объекта локали, который он содержит в качестве члена, и локали знают, как удалять указатели на все грани.

Верна ли Visual Studio и libc ++ неправильны?

* как реализовано в clang ++ - 2.9 / libc ++ - svn и Visual Studio 2010 EE SP1, следующий пример работает на обоих, но не на GCC, к сожалению: https://ideone.com/hywz6

1 Ответ

10 голосов
/ 29 сентября 2011

Я, по общему признанию, склонен в этом ответе. Но я попытаюсь подкрепить свои утверждения ссылками на 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()?

Это находится в p17 того же раздела ([conversions.string]):

~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"));

Надеюсь, это поможет.

...