皆さん御存知の通り、C++には std::error_category という物がある。

例えば std::system_category() は std::error_category から派生したクラス型のオブジェクトへの参照を返す。

おなじみcppjpの解説は

となっている。

まあそうだよな。

VS2013はconstexprに対応していないからまあそうなるわな。

あれ、気がついたらいつの間にか開いていた規格書ではconstexprにしろと書いてあるんだけど、なってないな・・・。

・・・ん？ _Addr ってなんだ。

どうやら比較演算子で使われているらしい。

ちょっとまって、規格書を見に行こう。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf

デフォルトコンストラクタはthisポインタを保存しているみたいだけど・・・なんでそんなことを？

この謎をとくために、 std::system_category という関数を見てみよう。

_Immortalize は規格書の要求を満たすためにstatic storageにクラスを構築するためのものなんだろう。(よく見たら微妙に違うみたいだけど)

ん！？なんかデフォルトコンストラクタがおかしいぞ・・・？

_System_addr ってなんだ？

・・・そういえば std::error_category の実装を載せた時にへんなenumがあったな

あった。ご丁寧にコメントが書いてある。

Google先生お願いします。

ほう・・・。つまり、 std::error_category クラスの比較演算子は、このenumによって作られた仮想的なアドレスを比較していると。

・・・いやそれってだめなんじゃ？もう一度規格書をみるよ。

ここでいう address はつまるところポインタのことじゃないのか？

cppjpでの @faithandbrave@github さんの解説も

と書いている。

VS2015は、それが規格的にいいのかは知らんが、 std::error_category の比較演算子の実装に仮想的なアドレスを使っている。

このせいで自分で std::error_category の派生クラスを作るときに困る。

皆さんに聞きたい、この実装ってありなの？

ん！？

STL Fixes In VS 2015, Part 2 | Visual C++ Team Blog

https://blogs.msdn.microsoft.com/vcblog/2015/07/14/stl-fixes-in-vs-2015-part-2/

* Error category objects didn’t behave properly across different DLLs/EXEs (DevDiv#666062, DevDiv#1095970/Connect#1053790). The tale of woe here was complicated. Calling generic_category(), for example, is supposed to return a reference to a single unique object, regardless of where it’s called. This is usually achieved by separate compilation into the STL’s DLL (or static LIB). However, we can’t separately compile error_category machinery, because it has a virtual message() returning std::string, whose representation is affected by ITERATOR_DEBUG_LEVEL. So, generic_category() is implemented header-only – but that means that different user DLLs end up with different instantiations and therefore different objects. (It’s also possible for this to cause trouble between a user’s EXE and the STL’s DLL.) We fixed this to achieve as much conformance as possible. We’ve taught error_category, its derived classes, and its operator==()/operator!=() to consider all genericcategory() objects to be equal, even if they live at different addresses in different DLLs (and similarly for the other error category objects in the Standard). This has been implemented so that user-defined error category objects will be unaffected. The only thing we can’t fix is a direct comparison of error_category addresses (code should use operator==() instead).

[C++] Comparison std::error_code from std::system_error to std::errc enum value incorrect when using DLL-version of run-time library

https://connect.microsoft.com/VisualStudio/feedback/details/1053790

A comparison of the error code from an std::system_error object thrown by std::thread to std::errc::resource_unavailable_try_again appears to produce an incorrect Boolean result when the application uses a DLL-specific version of the run-time library (compiler option "/MD" or "MDd").

The issue can be reproduces by the attached file, "MyTest.cpp", or by the online C++ compiler at http://rextester.com/EMVQXX20044

Christopher Kohlhoff encouraged me to submit this bug report. He suggested that the issue might be caused by the fact that the implementation compares error categories by their address, and from MSVC