2021年8月15日日曜日

24: 'std::codecvt<char16_t,char,struct _Mbstatet>'未解決エラー

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

Visual C++の2015以来のバグで、Microsoftが修正することを拒否していた(2019?まで)、説得力のない理由に基づいて。その問題をいかに回避するか。

話題


About: C++
About: Visual C++

この記事の目次


開始コンテキスト


  • 読者は、C++の基本的知識を持っている。

ターゲットコンテキスト



  • 読者は、'std::codecvt<char16_t,char,struct _Mbstatet>'未解決エラーは、2015以来の古いバグのせいであり、それは、Microsoftが修正することを拒否していた(2019?まで)ものであること、およびその問題を回避する方法を知る。

オリエンテーション


Visual C++の奇癖について、他にいくつかの記事があります(「unable to match function definition to an existing declaration」エラーDLLからシンボル群をエクスポートするコンストラクタテンプレートを明示的にインスタンス化する)。


本体

ト書き
Hypothesizer 7は、独白する。


1: 'std::codecvt<char16_t,char,struct _Mbstatet>'未解決エラーに遭遇する


Hypothesizer 7
以下のコードは、リンクエラー、「error LNK2001: unresolved external symbol "__declspec(dllimport) public: static class std::locale::id std::codecvt<char16_t,char,struct _Mbstatet>::id"」を発生させる、Visual C++ 2017では、GCCでは問題ないのであるが。

@C++ ソースコード
#include <codecvt>
#include <locale>

				wstring_convert <codecvt_utf8_utf16 <char16_t>, char16_t> l_wstringConverter;


2: その原因は、2015以来の古いバグであり、それを修正することをMicrosoftは拒否していた(2019?まで)


Hypothesizer 7
結局判明したことには、それは、Visual C++の古いバグであり、Visual C++ 2015以来、存在している . . .

それはあまりにも古すぎると言わせてもらう。プロダクトに若干のバグが忍び込む可能性があることは理解するが、バグはどれも、可能な限り速やかに修正されなければならないだろう。

このページに挙げられている、バイナリ互換性を維持するという理由が、当該バグを修正しないことを正当化するとは、私は同意しない。バイナリ互換性を維持することは、それ自体では理想的なことではあるが、C++スタンダードテンプレートライブラリとの互換性を破り続けることは、問題ないのであろうか? . . . セキュリティ脆弱性を包含するバグがもしあった場合、彼らは、バグ付きの古いバージョンとのバイナリ互換性を維持するために、バグを維持するのだろうか? . . .

悪い選択だ、と私は言う。

注釈しておくが、それは、ある時点(2019?厳密にいつなのかは私は知らない)で修正されたようだ、しかし、本記事(元々は、修正が行なわれる前に書かれたが、その後に、磨き直されて再投稿された)はそのまま記録として置いておく、古いバージョンをまだ使用している人がいるかもしれないというのはその理由の一部である。


3: 勧告された治癒方法、それは問題を解決しない


Hypothesizer 7
'char16_t'の代わりに'wchar_t'を使えばよいだろうと、彼らは勧告しているようだ、治癒方法として。

それが問題を解決するだろうか? . . . しない。私は、UTF8データを'u16string'データにコンバートするファンクションが欲しいのだ、以下のような。

@C++ ソースコード
#include <codecvt>
#include <locale>

			u16string getUtf16String (string const & a_utf8String) {
				wstring_convert <codecvt_utf8_utf16 <char16_t>, char16_t> l_wstringConverter;
				return l_wstringConverter.from_bytes (a_utf8String.data ());
			}

'char16_t'を'wchar_t'に変えると、'from_bytes'のリターンタイプを'wstring'に変えるが、私は'wstring'インスタンスなど欲しくなくて、'u16string'インスタンスが欲しいのだ . . .。注意しておくが、'wstring'インスタンスを単に'u16string'タイプにキャストするということはできない。


4: 回避策


Hypothesizer 7
結局のところ、私は、'wstring'インスタンスを使用して、'u16string'インスタンスを生成しなければならない、以下のように。

@C++ ソースコード
				wstring l_wstring = l_wstringConverter.from_bytes (a_utf8String.data ());
				return u16string (l_wstring.begin (),  l_wstring.end ());

そのコードはLinuxではうまくいかない(そこでは、'wchar_t'は'char16_t'とは長さが違う)ので 、以下のようなコードにしなければならない(LinuxでビルドすることはGCCを使うことだと仮定して)。

@C++ ソースコード
			u16string getUtf16String (string const & a_utf8String) {
#ifdef GCC
				wstring_convert <codecvt_utf8_utf16 <char16_t>, char16_t> l_wstringConverter;
				return l_wstringConverter.from_bytes (a_utf8String.data ());
#else
				wstring_convert <codecvt_utf8_utf16 <wchar_t>, wchar_t> l_wstringConverter;
				wstring l_wstring = l_wstringConverter.from_bytes (a_utf8String.data ());
				return u16string (l_wstring.begin (),  l_wstring.end ());
#endif
			}

そのようなことをしなければならないということは、私には嬉しくないのであるが。


参考資料


<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>