エラーコードについては、以前にこの状況に対処しました。
エラーコードに列挙型を使用している人を見たことがありますが、これにはいくつかの問題があります。
- どの値にも対応しない(あまりにも悪い)列挙型にintを割り当てることができます
- 値自体はヘッダーで宣言されます。つまり、エラーコードの再割り当て(これが発生します...)はコードの互換性を損ないます。要素を追加するときも注意する必要があります...
- 列挙型は「拡張」できないため、一部のコードがアプリケーションのごく一部に自然に制限されることがよくある場合でも、すべてのコードを同じヘッダーで定義する必要があります。
- 同じコードが2回割り当てられていないというチェックはありません
- のさまざまなフィールドを反復処理することはできません
enum
エラーコードソリューションを設計するとき、私は別の道を選びました。名前空間の定数で、ソースファイルで定義され、ポイント2と3に対応します。ただし、型の安全性を高めるために、定数はではなくint
、特定のCode
クラスです。
namespace error { class Code; }
次に、いくつかのエラーファイルを定義できます。
// error/common.hpp
namespace error
{
extern Code const Unknown;
extern Code const LostDatabaseConnection;
extern Code const LostNASConnection;
}
// error/service1.hpp
// error/service2.hpp
ただし、任意のキャストの問題は解決しませんでした(コンストラクターは明示的ですが公開されています)。私の場合、他のサーバーから返されたエラーコードを転送する必要があり、それらすべてを知りたくなかったためです(もろすぎたでしょう)
ただし、必要なコンストラクターをプライベートにし、ビルダーの使用を強制することで、4と5を一気に取得することもできます。
// error/code.hpp
namespace error
{
class Code;
template <size_t constant> Code const& Make(); // not defined here
class Code: boost::totally_ordered<Code>
{
public:
Code(): m(0) {} // Default Construction is useful, 0 is therefore invalid
bool operator<(Code const& rhs) const { return m < rhs.m; }
bool operator==(Code const& rhs) const { return m == rhs.m; }
private:
template <size_t> friend Code const& Make();
explicit Code(size_t c): m(c) { assert(c && "Code - 0 means invalid"); }
size_t m;
};
std::set<Code> const& Codes();
}
// error/privateheader.hpp (inaccessible to clients)
namespace error
{
std::set<Code>& PrivateCodes() { static std::set<Code> Set; return Set; }
std::set<Code> const& Codes() { return PrivateCodes(); }
template <size_t constant>
Code const& Make()
{
static std::pair< std::set<Code>::iterator, bool > r
= PrivateCodes().insert(Code(constant));
assert(r.second && "Make - same code redeclared");
return *(r.first);
}
}
//
// We use a macro trick to create a function whose name depends
// on the code therefore, if the same value is assigned twice, the
// linker should complain about two functions having the same name
// at the condition that both are located into the same namespace
//
#define MAKE_NEW_ERROR_CODE(name, value) \
Make<value>(); void _make_new_code_##value ();
// error/common.cpp
#include "error/common.hpp"
#include "privateheader.hpp"
namespace error
{
Code const Unkown = MAKE_NEW_ERROR_CODE(1)
/// ....
}
(フレームワークの場合)もう少し作業が必要で、同じ割り当てチェックのリンク時/実行時チェックのみです。パターンをスキャンするだけで重複を診断するのは簡単ですがMAKE_NEW_ERROR_CODE
楽しむ!