std::wstring_convertとstd::wstring_bufferって、std::localeと組み合わて使うのが難しいです。そんなわけで、その名前とは裏腹にstd::wstring (wchar_t)との組み合わせには使いづらいなあと思っています。

が、しかし、Visual C++はその辺、規格をいい感じにやっちゃって(無視して)いて、使えるようになっていることに気付いてしまいました。

このコード、コンパイルできてしまいました。もちろん、実行すればちゃんと動きます。

#include <codecvt>
#include <locale>
#include <string>
#include <iostream>
 
int main()
{
  using codecvt_wchar = std::codecvt<wchar_t, char, std::mbstate_t>;
 
  std::locale loc("");
  std::wstring_convert<codecvt_wchar> cv(
    &std::use_facet<codecvt_wchar>(loc));
 
  std::string message = "あいうえお";
 
  std::wstring wcs = cv.from_bytes(message);
  std::string mbs = cv.to_bytes(wcs);
 
  std::cout << mbs << std::endl;
}

wbuffer_convertも同様にコンパイルできました。

#include <codecvt>
#include <locale>
#include <string>
#include <iostream>
#include <sstream>
 
int main()
{
  using codecvt_wchar = std::codecvt<wchar_t, char, std::mbstate_t>;
 
  std::locale loc("");
 
  std::wstring_convert<codecvt_wchar> cv(
    &std::use_facet<codecvt_wchar>(loc));
 
  std::wbuffer_convert<codecvt_wchar> buf(
    std::cout.rdbuf(),
    &std::use_facet<codecvt_wchar>(loc));
  std::wostream my_wcout(&buf);
 
  std::wstring wcs = cv.from_bytes("かきくけこ");
  my_wcout << wcs << std::endl;
}

「こういう風に書くとダメなんですよー」という例を出すつもりで書き始めたら、逆にコンパイルエラーが出なくて、驚きました。

  • wstring_convertおよびwstring_bufferのコンストラクタがコンパイルできている。標準規格では、仮引数の型が非constなポインタ型となっているのに、VC++ではconstなポインタ型となっている。use_facetの戻り値の型はconstな参照なのだが、そのせいでコンパイルが通る。
  • wstring_convertおよびwstring_bufferのデストラクタがコンパイルできている。デストラクタでは、コンストラクタで渡したcodecvtへのポインタをdeleteすることになっているのだが、std::codecvtのデストラクタはprotected。VC++のwstring_convertとwbuffer_convertは、内部でstd::localeオブジェクトにcodecvtを持たせることで、この問題を回避している。

GCC (libstdc++)やClang (libc++)だといずれもコンパイルエラーです。

この実装、私がこういう風に使えたら良かったと考えていた感じです。その点では素晴らしいのですが、現実VC++だけが標準規格に沿っていないという現状では、あまり有用に使えないのですよね。

2017年1月15日追記: 後者について、開発元に質問が出ているのを見かけています: [Visual C++] Is it accepted std::wstring_convert/std::wbuffer_convert delete std::codecvt pointer ? – Developer Community

スポンサード リンク

この記事のカテゴリ

  • ⇒ VC++のwstring_convertやwbuffer_convertがちょっと変
  • ⇒ VC++のwstring_convertやwbuffer_convertがちょっと変