Visual C++ 2015および2017 RCでは、<codecvt>の各クラステンプレートにchar16_tやchar32_tを組み合わせるとリンクエラーになるという問題があります。今回、これに対する条件付きのWorkaroundについて書きます。
まずは、エラーになるコードの例を提示します。
#include
#include
#include
#include
int main()
{
std::wstring_convert, char32_t> converter_utf32;
std::wstring_convert, char16_t> converter_utf16;
std::string u8str = u8"\U0001F359";
std::u32string u32str = converter_utf32.from_bytes(u8str);
std::u16string u16str = converter_utf16.from_bytes(u8str);
}
これをVisual C++ 2015でコンパイル・リンクするとこんなエラーメッセージが出てきます。
u.obj : error LNK2019: 未解決の外部シンボル "public: static class std::locale::id std::codecvt::id" (?id@?$codecvt@_SDU_Mbstatet@@@std@@2V0locale@2@A) が関数 "public: __thiscall std::locale::locale >(class std::locale const &,class std::codecvt_utf8_utf16 const *)" (??$?0V?$codecvt_utf8_utf16@_S$0BAPPPP@$0A@@std@@@locale@std@@QAE@ABV01@PBV?$codecvt_utf8_utf16@_S$0BAPPPP@$0A@@1@@Z) で参照されました。 u.obj : error LNK2019: 未解決の外部シンボル "public: static class std::locale::id std::codecvt ::id" (?id@?$codecvt@_UDU_Mbstatet@@@std@@2V0locale@2@A) が関数 "public: __thiscall std::locale::locale >(class std::locale const &,class std::codecvt_utf8 const *)" (??$?0V?$codecvt_utf8@_U$0BAPPPP@$0A@@std@@@locale@std@@QAE@ABV01@PBV?$codecvt_utf8@_U$0BAPPPP@$0A@@1@@Z) で参照されました。 u.exe : fatal error LNK1120: 2 件の未解決の外部参照
さて、エラーメッセージを読むと、1件目はstd::locale::id型のstaticメンバー変数std::codecvt<char16_t,char,struct _Mbstatet>::idが見つからないという内容です。2件目も同じ内容でchar32_tになっているだけです。ということは、これを自分で定義したら良いのではないでしょうか?
というわけで、こんなコードを書いたらうまくいきました。コンパイル・リンクできてちゃんと実行できました。
#include
#include
#include
#include
// この2行を追加
std::locale::id std::codecvt::id;
std::locale::id std::codecvt::id;
int main()
{
std::wstring_convert, char32_t> converter_utf32;
std::wstring_convert, char16_t> converter_utf16;
std::string u8str = u8"\U0001F359";
std::u32string u32str = converter_utf32.from_bytes(u8str);
std::u16string u16str = converter_utf16.from_bytes(u8str);
}
ただし、この方法を使うには条件があります。それは、VC++ランタイムを静的リンクする場合(/MTや/MTdコンパイルオプション)だけ使えるというものです。/MDや/MDdだと、問題となるstaticメンバー変数idが__declspec(dllimport)
付きの宣言となってしまうため、この方法が使えません。別のリンクエラーになります。
ところで、以下のcpprefjpの各ページのサンプルコードもこの問題に該当します。それぞれのサンプルコードの作成にあたり、私はこの方法で乗り切りました。
まとめです。
- codecvt_utf16, codecvt_utf8, codecvt_utf8_utf16のいずれかに、char16_tかchar32_tを使うとリンクエラーが出る。
- そうなったら、codecvtクラステンプレートののstaticメンバー変数idを自分で定義すれば、リンクが通る。
バグ報告は出ているそう(Visual C++における文字コード変換 – C++と色々)なので、将来的にはVisual C++が直ることを期待します。あと/MD, /MDdでのWorkaround欲しいです。
VC++ 2015のcodecvtでリンクエラーになる問題の回避策 is a post from: イグトランスの頭の中