C++でbit演算を簡単に行う方法
ビット演算の細かいことは以下の記事を参考にしてください。
[追記]
テンプレートでやってく出さっている方がいらっしゃったのでこちらを参考にしてください!
では本題のbit演算を簡単に行う方法の実装方法について説明していきます。
※あと、このコードの著作権に関しては正直分かりません。
少なくともVC++17のヘッダの最上部・最下部に著作権明記らしきものがなかったので多分大丈夫ではないかと思います。
[追記]著作権に関してはマイクロソフトの公式docsを見た方が良さそうです。
_BITMASK_OPSマクロ
このマクロを使用します。
このマクロは渡されたenum classに対する演算子オーバーロードを全て作成してくれる優秀なマクロです。
私はたまたま、このマクロを見つけたときにええもん見つけたっと思ったくらいに優秀です。はい。
実装
マクロを定義したファイル
// 多分このマクロが入っているはずです。
// 私はVC++17でこのマクロを見つけたのですが、それ以外は確認していませんがなにとぞ。
// なければ以下のコードを全てコピペしてファイルに張り付けてください。
#include<type_traits>
#ifndef _STD
#define _STD std::
#endif
// [[nodiscard]]属性はC++17以降のみに実装されているのでそれ以前の場合は使用できない
#ifdef _MSVC_LANG
// exist _MSVC_LANG macro
#if _MSVC_LANG > 201703L
#ifndef _NODISCARD
#define _NODISCARD [[nodiscard]]
#endif
#endif
//no exist _MSVC_LANG macro
#else
#if __cplusplus > 201703L
#ifndef _NODISCARD
#define _NODISCARD [[nodiscard]]
#endif
#endif
#endif
// <type_traits>をincludeした際にマクロの定義が被らないようにしておく
#ifndef _BITMASK_OPS
// BITMASK OPERATIONS
#define _BITMASK_OPS(_BITMASK) \
_NODISCARD constexpr _BITMASK operator&(_BITMASK _Left, _BITMASK _Right) noexcept \
{ /* return _Left & _Right */ \
using _IntTy = _STD underlying_type_t<_BITMASK>; \
return (static_cast<_BITMASK>(static_cast<_IntTy>(_Left) & static_cast<_IntTy>(_Right))); \
} \
\
_NODISCARD constexpr _BITMASK operator|(_BITMASK _Left, _BITMASK _Right) noexcept \
{ /* return _Left | _Right */ \
using _IntTy = _STD underlying_type_t<_BITMASK>; \
return (static_cast<_BITMASK>(static_cast<_IntTy>(_Left) | static_cast<_IntTy>(_Right))); \
} \
\
_NODISCARD constexpr _BITMASK operator^(_BITMASK _Left, _BITMASK _Right) noexcept \
{ /* return _Left ^ _Right */ \
using _IntTy = _STD underlying_type_t<_BITMASK>; \
return (static_cast<_BITMASK>(static_cast<_IntTy>(_Left) ^ static_cast<_IntTy>(_Right))); \
} \
\
constexpr _BITMASK& operator&=(_BITMASK& _Left, _BITMASK _Right) noexcept \
{ /* return _Left &= _Right */ \
return (_Left = _Left & _Right); \
} \
\
constexpr _BITMASK& operator|=(_BITMASK& _Left, _BITMASK _Right) noexcept \
{ /* return _Left |= _Right */ \
return (_Left = _Left | _Right); \
} \
\
constexpr _BITMASK& operator^=(_BITMASK& _Left, _BITMASK _Right) noexcept \
{ /* return _Left ^= _Right */ \
return (_Left = _Left ^ _Right); \
} \
\
_NODISCARD constexpr _BITMASK operator~(_BITMASK _Left) noexcept \
{ /* return ~_Left */ \
using _IntTy = _STD underlying_type_t<_BITMASK>; \
return (static_cast<_BITMASK>(~static_cast<_IntTy>(_Left))); \
} \
\
_NODISCARD constexpr bool _Bitmask_includes(_BITMASK _Left, _BITMASK _Elements) noexcept \
{ /* return (_Left & _Elements) != _BITMASK{} */ \
using _IntTy = _STD underlying_type_t<_BITMASK>; /* TRANSITION, VSO#574589 */ \
return (static_cast<_IntTy>(_Left & _Elements) != 0); \
} \
\
_NODISCARD constexpr bool _Bitmask_includes_all(_BITMASK _Left, _BITMASK _Elements) noexcept \
{ /* return (_Left & _Elements) == _Elements */ \
return ((_Left & _Elements) == _Elements); \
}
#endif
enum class BitMask : unsigned int{
A = 0x1, // 1
B = 0x2 // 2
}
// これで演算子オーバーロードを使用可能
_BITMASK_OPS( BitMask )
int main(){
BitMask a = BitMask::A;
BitMask ab = BitMask::A | BitMask::B;
if( ( BitMask::A & a ) == BitMask::A ) {
std::cout << static_cast<unsigned int>( a ) << std::endl;
}
if( ab == ( BitMask::A | BitMask::B ) ) {
std::cout << static_cast< unsigned int >( ab ) << std::endl;
}
}
最後に
やっぱり公式のファイルはたまに見るといいコードが見れるのでいいですね。
これを機に皆さんも公式のファイルの中身を見てみてはいかかでしょうか。
歴戦のC++erのコードが見れて楽しいですよw
それでは。