Enumクラスを使用して、標準準拠(n3242ドラフトの17.5.2.1.3で説明されている)タイプセーフビットマスクを実装できますか?私がそれを読む方法、タイプTはそれが|、&、^、〜、| =、&=および^ =演算子をサポートしている場合、ビットマスクであり、さらに、lおよびrがタイプTであるif(l&r)を行うことができます。リストにないのは演算子!=と==であり、ソートを可能にするために、おそらく<もオーバーロードしたいと思うでしょう。
演算子を機能させることは、ボイラープレートコードを煩わせるだけですが、if(l&r)の実行方法はわかりません。少なくとも以下はGCCでコンパイルされません(intへの誤った暗黙の変換を可能にするため、非常に危険であることに加えて):
enum class Foo{
operator bool(){
return (unsigned)*this;
}
};
編集:私は今、列挙型クラスがメンバーを持つことができないことを確かに知っています。 if(l&r)が残っている場合の実際の質問はどうですか。
私はできると思います...あなたはビットマスクのために演算子を追加する必要があります。ここではそれをしませんでしたが、関係演算子を簡単にオーバーロードする可能性があります。
/**
*
*/
// NOTE: I changed to a more descriptive and consistent name
// This needs to be a real bitmask type.
enum class file_permissions : int
{
no_perms = 0,
owner_read = 0400,
owner_write = 0200,
owner_exe = 0100,
owner_all = 0700,
group_read = 040,
group_write = 020,
group_exe = 010,
group_all = 070,
others_read = 04,
others_write = 02,
others_exe = 01,
others_all = 07,
all_all = owner_all | group_all | others_all, // 0777
set_uid_on_exe = 04000,
set_gid_on_exe = 02000,
sticky_bit = 01000,
perms_mask = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit, // 07777
perms_not_known = 0xffff,
add_perms = 0x1000,
remove_perms = 0x2000,
symlink_perms = 0x4000
};
inline constexpr file_permissions
operator&(file_permissions x, file_permissions y)
{
return static_cast<file_permissions>
(static_cast<int>(x) & static_cast<int>(y));
}
inline constexpr file_permissions
operator|(file_permissions x, file_permissions y)
{
return static_cast<file_permissions>
(static_cast<int>(x) | static_cast<int>(y));
}
inline constexpr file_permissions
operator^(file_permissions x, file_permissions y)
{
return static_cast<file_permissions>
(static_cast<int>(x) ^ static_cast<int>(y));
}
inline constexpr file_permissions
operator~(file_permissions x)
{
return static_cast<file_permissions>(~static_cast<int>(x));
}
inline file_permissions &
operator&=(file_permissions & x, file_permissions y)
{
x = x & y;
return x;
}
inline file_permissions &
operator|=(file_permissions & x, file_permissions y)
{
x = x | y;
return x;
}
inline file_permissions &
operator^=(file_permissions & x, file_permissions y)
{
x = x ^ y;
return x;
}
受け入れ基準が何であるかは完全にはわかりませんが、operator &
に適切な変換とexplicit operator bool
を含むラッパークラスを返させるだけでかまいません。
#include <type_traits>
template<typename T> using Underlying = typename std::underlying_type<T>::type;
template<typename T> constexpr Underlying<T>
underlying(T t) { return Underlying<T>(t); }
template<typename T> struct TruthValue {
T t;
constexpr TruthValue(T t): t(t) { }
constexpr operator T() const { return t; }
constexpr explicit operator bool() const { return underlying(t); }
};
enum class Color { RED = 0xff0000, GREEN = 0x00ff00, BLUE = 0x0000ff };
constexpr TruthValue<Color>
operator&(Color l, Color r) { return Color(underlying(l) & underlying(r)); }
もちろん、他のすべての演算子はColor
を返し続けることができます。
constexpr Color
operator|(Color l, Color r) { return Color(underlying(l) | underlying(r)); }
constexpr Color operator~(Color c) { return Color(~underlying(c)); }
int main() {
constexpr Color YELLOW = Color::RED | Color::GREEN;
constexpr Color WHITE = Color::RED | Color::GREEN | Color::BLUE;
static_assert(YELLOW == (WHITE & ~Color::BLUE), "color subtraction");
return (YELLOW & Color::BLUE) ? 1 : 0;
}
スコープ付き列挙型(enum class
またはenum struct
で作成されたもの)はクラスではありません。メンバー関数を持つことはできず、囲まれた列挙子を提供するだけです(名前空間レベルでは表示されません)。
リストにないのは演算子!=と==です。
これらの演算子は、列挙型、整数型、および_std::bitset
_ですでにサポートされているため、それらをオーバーロードする必要はありません。
並べ替えを許可するには、おそらく<もオーバーロードする必要があります。
なぜビットマスクをソートしたいのですか? (a | b)は(a | c)よりも大きいですか? _std::ios::in
_は_std::ios::app
_よりも小さいですか?それは重要ですか?関係演算子は、列挙型と整数型に対して常に定義されています。
主な質問に答えるには、_&
_をオーバーロードされたnon-member関数として実装します。
_Foo operator&(Foo l, Foo r)
{
typedef std::underlying_type<Foo>::type ut;
return static_cast<Foo>(static_cast<ut>(l) & static_cast<ut>(r));
}
_
ビットマスク型に必要なすべての操作はスコープ付き列挙型に対して定義できると思いますが、次のような要件はありません
Ci&Cjはゼロではなく、Ci&Cjはゼロです
そして:
値Yはオブジェクトに設定されています[〜#〜] x [〜#〜]は式X&Yはゼロ以外です。
スコープ付き列挙型は整数型への暗黙的な変換をサポートしていないため、それがゼロでないかどうかを確実にテストすることはできません。 if ((X&Y) != bitmask{})
と書く必要がありますが、それは委員会の意図ではないと思います。
(最初はビットマスク型の定義に使用できると思っていましたが、スコープ付き列挙型を使用して実装しようとしたところ、ゼロ/非ゼロのテストで問題が発生したことを思い出しました。)
編集:私はちょうど_std::launch
_がスコープ付き列挙型およびビットマスク型であることを思い出しました...そのため、明らかにスコープ付き列挙型はビットマスク型である可能性があります!
以下の列挙型フラグの短い例。
#indlude "enum_flags.h"
ENUM_FLAGS(foo_t)
enum class foo_t
{
none = 0x00
,a = 0x01
,b = 0x02
};
ENUM_FLAGS(foo2_t)
enum class foo2_t
{
none = 0x00
,d = 0x01
,e = 0x02
};
int _tmain(int argc, _TCHAR* argv[])
{
if(flags(foo_t::a & foo_t::b)) {};
// if(flags(foo2_t::d & foo_t::b)) {}; // Type safety test - won't compile if uncomment
};
ENUM_FLAGS(T)はマクロであり、 enum_flags.h で定義されています(100行未満、制限なしで自由に使用できます)。