我有几个枚举我想用作按位标志。我可以为所有这些代码编写代码,而不会影响那些我不想以这种方式对待的代码吗?
答案 0 :(得分:2)
您可以使用专业化在功能上标记合适的枚举和SFINAE:
template<typename E> struct is_bitwise_enum : std::false_type {};
现在标记所有的按位枚举:
template<> struct is_bitwise_enum< my_enum > : std::true_type {};
template<> struct is_bitwise_enum< my_other_enum > : std::true_type {};
并保护这样的功能:
template<typename E>
typename std::enable_if<is_bitwise_enum<E>::value,E>::type
operator|(const E lhs, const E rhs) { ... }
答案 1 :(得分:0)
是的,通过使用类型特征和SFINAE,您可以指定函数/运算符可以与枚举一起使用。
我完成了我的头文件并决定使用Daniel Frey所描述的专业化想法进行分享,以防任何人想要或想要在其上构建。
#ifdef _MSC_VER
#pragma once // For VC++
#endif
#ifndef ENUM_FUNCTIONS_H
#define ENUM_FUNCTIONS_H
///////////////////////////////////////////////////////////////////////////////
// Common enum functions so that the same code doesn't have to be written over
// and over again for different enums.
//
// -- Written by: Adrian Hawryluk, June 2015
///////////////////////////////////////////////////////////////////////////////
#include <type_traits>
namespace enums
{
size_t const version = 1;
// If your compiler doesn't understand constexpr, then set CONSTEXPR to blank,
// otherwise set to constexpr.
#define CONSTEXPR //constexpr
///////////////////////////////////////////////////////////////////////////
// Use Enums as Bit Flags
//
// These functions allow the treating of an enum as a set of bits with
// which you can use a subset of the standard bitwise operators:
//
// |, |=, &, &=, ^, ^=
//
// and the functions:
//
// Cast, CastRef, CastSigned, CastSignedRef, CastUnsigned, CastUnsignedRef,
// MakeSet, Set, MakeClear, Clear, MakeToggle, Toggle, AreAllSet,
// AreAnySet, AreAllClear, AreAnyClear, FirstSet, FirstCleared
//
// To enable the use of these operators and functions, define:
//
// namespace enums {
// template<> struct is_bitflag_enum<my_enum> : std::true_type {};
// }
//
// where my_enum is the enum being defined to use these functions.
//
// To be able to use the operators, you need to state that you are using the
// namespace in the appropriate scope:
//
// using namespace enums;
template<typename E> struct is_bitflag_enum : std::false_type {};
// operator ^=
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E&>::type
operator^=(E& lhs, E rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E&)((uint_t&)lhs ^= (uint_t)rhs);
}
// operator ~
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
operator~(E rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E)(~(uint_t)rhs);
}
// operator |=
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E&>::type
operator|=(E& lhs, E rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E&)((uint_t&)lhs |= (uint_t)rhs);
}
// operator |
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
operator|(E lhs, E rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E)((uint_t)lhs | (uint_t)rhs);
}
// operator &=
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E&>::type
operator&=(E& lhs, E rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E&)((uint_t&)lhs &= (uint_t)rhs);
}
// operator &
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
operator&(E lhs, E rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E)((uint_t)lhs & (uint_t)rhs);
}
// MakeSet(initialFlagState, flagModification)
//
// Sets the on bits in flagModification to on in initialFlagState.
// initialFlagState is NOT modified, but returs a new value
// (i.e. "Makes" a new value).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
MakeSet(E initialFlagState, E flagModification)
{
return initialFlagState | flagModification;
}
// Set(initialFlagState, flagModification)
//
// Sets the on bits in flagModification to on in initialFlagState.
// initialFlagState is modified, and returs a reference to that variable.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E&>::type
Set(E& initialFlagState, E flagModification)
{
return initialFlagState |= flagModification;
}
// MakeClear(initialFlagState, flagModification)
//
// Clears the on bits in flagModification to off in initialFlagState.
// initialFlagState is NOT modified, but returs a new value
// (i.e. "Makes" a new value).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
MakeClear(E initialFlagState, E flagModification)
{
return initialFlagState & ~flagModification;
}
// Clear(initialFlagState, flagModification)
//
// Clears the on bits in flagModification to off in initialFlagState.
// initialFlagState is modified, and returs a reference to that variable.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E&>::type Clear(E& initialFlagState, E flagModification)
{
return initialFlagState &= ~flagModification;
}
// MakeToggle(initialFlagState, flagModification)
//
// Toggles the on bits in flagModification in initialFlagState.
// initialFlagState is NOT modified, but returs a new value
// (i.e. "Makes" a new value).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
MakeToggle(E initialFlagState, E flagModification)
{
return initialFlagState ^ flagModification;
}
// Toggle(initialFlagState, flagModification)
//
// Toggles the on bits in flagModification in initialFlagState.
// initialFlagState is modified, and returs a reference to that variable.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E&>::type
Toggle(E& initialFlagState, E flagModification)
{
return initialFlagState ^= flagModification;
}
// AreAllSet(flagState, flagsToCompare)
//
// Returns true if all bits in flagToCompare are set in flagState,
// false otherwise.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
bool>::type
AreAllSet(E flagState, E flagsToCompare)
{
return (flagState & flagsToCompare) == flagsToCompare;
}
// AreAnySet(flagState, flagsToCompare)
//
// Returns true if any bits in flagToCompare are set in flagState,
// false otherwise.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
bool>::type
AreAnySet(E flagState, E flagsToCompare)
{
return (flagState & flagsToCompare) != (E)0;
}
// AreAllClear(flagState, flagsToCompare)
//
// Returns true if all bits in flagToCompare are cleared in flagState,
// false otherwise.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
bool>::type
AreAllClear(E flagState, E flagsToCompare)
{
return (~flagState & flagsToCompare) == flagsToCompare;
}
// AreAnyClear(flagState, flagsToCompare)
//
// Returns true if any bits in flagToCompare are cleared in flagState,
// false otherwise.
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
bool>::type
AreAnyClear(E flagState, E flagsToCompare)
{
return (~flagState & flagsToCompare) != (E)0;
}
// FirstSet(flagState, flagToCompare)
//
// Return the first flag in the list that is set in flagState.
// If all are not set, return (E)0.
//
// NOTE: If a flag in the list is (E)0, then it will ignore that element
// in the list, and continue to the next one.
// NOTE: If a flag in the list represents 2 or more bits, only a subset of
// those bits need be set to result in the returned value.
template<typename E, typename ...Es>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
FirstSet(E flagState, E flagToCompare)
{
if (AreAnySet(flagState, flagToCompare))
{
return flagToCompare;
}
return (E)0;
}
// FirstSet(flagState, flagToCompare, ...)
//
// Return the first flag in the list that is set in flagState.
// If all are not set, return (E)0.
//
// NOTE: If a flag in the list is (E)0, then it will ignore that element
// in the list, and continue to the next one.
// NOTE: If a flag in the list represents 2 or more bits, only a subset of
// those bits need be set to result in the returned value.
template<typename E, typename ...Es>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
FirstSet(E flagState, E flagToCompare, Es...flagsToCompare)
{
if (AreAnySet(flagState, flagToCompare))
{
return flagToCompare;
}
return FirstSet(flagState, flagsToCompare...);
}
// FirstCleared(flagState, flagToCompare)
//
// Return the first flag in the list that is NOT set in flagState.
// If all are not set, return (E)0.
//
// NOTE: If a flag in the list is (E)0, then it will not go beyond that
// element in the list.
// NOTE: If a flag in the list represents 2 or more bits, only a subset of
// those bits need be cleared to result in the returned value.
template<typename E, typename ...Es>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
FirstCleared(E flagState, E flagToCompare)
{
if (AreAnyClear(flagState, flagToCompare))
{
return (E)0;
}
return flagToCompare;
}
// FirstCleared(flagState, flagToCompare, ...)
//
// Return the first flag in the list that is cleared in flagState.
// If all are cleared, return (E)0.
//
// NOTE: If a flag in the list is (E)0, then it will not go beyond that
// element in the list.
// NOTE: If a flag in the list represents 2 or more bits, only a subset of
// those bits need be cleared to result in the returned value.
template<typename E, typename ...Es>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value,
E>::type
FirstCleared(E flagState, E flagToCompare, Es...flagsToCompare)
{
if (AreAnyClear(flagState, flagToCompare))
{
return FirstCleared(flagState, flagsToCompare...);
}
return flagToCompare;
}
///////////////////////////////////////////////////////////////////////////
// Use With Shift Operators
//
// These functions allow the treating of an enum as a siftable set of bits
// with which you can use a subset of the standard bitwise operators:
//
// <<, <<=, >>, >>=
//
// and the functions:
//
// Cast, CastRef, CastSigned, CastSignedRef, CastUnsigned, CastUnsignedRef
//
// To enable the use of these operators and functions, define:
//
// namespace enums {
// template<> struct is_shiftable_enum<my_enum> : std::true_type {};
// }
//
// where my_enum is the enum being defined to use these functions.
//
// To be able to use the operators, you need to state that you are using the
// namespace in the appropriate scope:
//
// using namespace enums;
template<typename E> struct is_shiftable_enum : std::false_type {};
// operator <<
template<typename E>
CONSTEXPR typename std::enable_if<is_shiftable_enum<E>::value,
E>::type
operator<<(E lhs, int rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E)(((uint_t)lhs) << rhs);
}
// operator <<=
template<typename E>
CONSTEXPR typename std::enable_if<is_shiftable_enum<E>::value,
E&>::type
operator<<=(E& lhs, int rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E&)(((uint_t&)lhs) <<= rhs);
}
// operator >>
template<typename E>
CONSTEXPR typename std::enable_if<is_shiftable_enum<E>::value,
E>::type
operator>>(E lhs, int rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E)(((uint_t)lhs) << rhs);
}
// operator >>=
template<typename E>
CONSTEXPR typename std::enable_if<is_shiftable_enum<E>::value,
E&>::type
operator>>=(E& lhs, int rhs)
{
typedef typename std::make_unsigned<typename std::underlying_type<E>::type>::type uint_t;
return (E&)(((uint_t&)lhs) <<= rhs);
}
///////////////////////////////////////////////////////////////////////////
// Casting functions
//
// These functions are to cast the enum to the underlying type, some of
// which allowing to coerce the type to be signed or not.
// Cast enum to the underlying type reference (lvalue).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value || is_shiftable_enum<E>::value,
typename std::underlying_type<E>::type>::type&
CastRef(E& flagState)
{
return (decltype(CastRef(flagState)))flagState;
}
// Cast enum to a signed integer reference (lvalue).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value || is_shiftable_enum<E>::value,
typename std::make_signed<typename std::underlying_type<E>::type>::type>::type&
CastSignedRef(E& flagState)
{
return (decltype(CastSignedRef(flagState)))flagState;
}
// Cast enum to an unsigned integer reference (lvalue).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value || is_shiftable_enum<E>::value,
typename std::make_unsigned<typename std::underlying_type<E>::type>::type>::type&
CastUnsignedRef(E& flagState)
{
return (decltype(CastUnsignedRef(flagState)))flagState;
}
// Cast enum to the underlying type value (rvalue).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value || is_shiftable_enum<E>::value,
typename std::underlying_type<E>::type>::type
Cast(E flagState)
{
return (decltype(Cast(flagState)))flagState;
}
// Cast enum to a signed integerr value (rvalue).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value || is_shiftable_enum<E>::value,
typename std::make_signed<typename std::underlying_type<E>::type>::type>::type
CastSigned(E flagState)
{
return (decltype(CastSigned(flagState)))flagState;
}
// Cast enum to an unsigned integerr value (rvalue).
template<typename E>
CONSTEXPR typename std::enable_if<is_bitflag_enum<E>::value || is_shiftable_enum<E>::value,
typename std::make_unsigned<typename std::underlying_type<E>::type>::type>::type
CastUnsigned(E flagState)
{
return (decltype(CastUnsigned(flagState)))flagState;
}
#undef CONSTEXPR
}
#endif // ENUM_FUNCTIONS_H
在包含的代码中,枚举可以通过指定
来访问这些功能namespace enums {
template<> struct is_shiftable_enum<my_enum> : std::true_type {};
}
my_enum
是您要授予访问权限的枚举。使用运算符时,您必须指定using namespace enums;
,以便运算符可以在您使用它的范围内工作。