Skip to content

Instantly share code, notes, and snippets.

@Broxzier
Last active April 8, 2018 21:57
Show Gist options
  • Save Broxzier/bbd86d9503ffaaadd02f2f4dffc6ca37 to your computer and use it in GitHub Desktop.
Save Broxzier/bbd86d9503ffaaadd02f2f4dffc6ca37 to your computer and use it in GitHub Desktop.
/// header_1.h =====
enum class SurfacePropertyMasks
{
SlopeRaisedCornersMask = 0b0001111,
SlopeDiagonalFlag = 0b00010000,
SlopeMask = SlopeRaisedCornersMask | SlopeDiagonalFlag,
EdgeStyleMask = 0b11100000,
SurfaceWaterHeightMask = 0b00011111,
SurfaceTerrainMask = 0b11100000,
};
/// header_2.h =====
enum class RideEntryFlags
{
VehicleTabScaleHalf = 1 << 0,
NoInversions = 1 << 1,
NoBankedTrack = 1 << 2,
PlayDepartSound = 1 << 3,
AlternativeSwingMode1 = 1 << 4,
AlternativeRotationMode1 = 1 << 5, // Twist type rotation ride
AlternativeRotationMode2 = 1 << 6, // Lifting arm rotation ride (enterprise)
Flag7 = 1 << 7,
PlaySplashSound = 1 << 8,
PlaySplashSoundSlide = 1 << 9,
CoveredRide = 1 << 10,
LimitAirtimeBonus = 1 << 11,
SeparateRideNameDeprecated = 1 << 12, // Always set with SEPARATERIDE, and deprecated in favour of it.
SeparateRideDeprecated = 1 << 13, // Made redundant by ride groups
CannotBreakDown = 1 << 14,
DisableLastOperatingMode = 1 << 15,
Flag16 = 1 << 16,
DisableFirstTwoOperatingModes = 1 << 17,
Flag18 = 1 << 18,
DisableColourTab = 1 << 19,
AlternativeSwingMode2 = 1 << 20, // Must be set with swing mode 1 as well.
};
#include <openrct2/core/Guard.hpp>
#include <openrct2/util/EnumClassHelper.hpp>
#include "header_1.h"
#include "header_2.h"
enum class UnrecognizedEnumClass
{
Value = 1,
};
void TestFunc()
{
// For both implementations a compilation error is thrown for unrecognized enum class types
auto ttt = UnrecognizedEnumClass::Value;
ttt |= UnrecognizedEnumClass::Value; // error C2893: Failed to specialize function template 'enable_if<_Test,_Ty>::type operator |=(T &,T)'
ttt &= UnrecognizedEnumClass::Value; // (static_assert) error C2338: Type is not an openrct2 enum class
// For recognized enum class types however, the bitwise operator overloads can be used
RideEntryFlags rideFlags = RideEntryFlags::NoBankedTrack;
rideFlags |= RideEntryFlags::CoveredRide;
// But only with the same type (can be desirable, but would requite a lot of refactoring)
auto val = rideFlags & unsigned char(1); // error C2782: template parameter is ambiguous
// The return value is also a strong type
if (rideFlags & RideEntryFlags::NoBankedTrack); // error C2451: conditional expression of type 'RideEntryFlags' is illegal
if(static_cast<bool>(rideFlags & RideEntryFlags::NoBankedTrack)); // This works
// Edge case: doesn't work well with volatile (not used though), but can probably be worked around with more type_traits
volatile auto surfaceFlags = SurfacePropertyMasks::SlopeRaisedCornersMask & SurfacePropertyMasks::SlopeDiagonalFlag;
surfaceFlags &= SurfacePropertyMasks::SlopeDiagonalFlag; // error C2782: converting `volatile SurfacePropertyMasks` to `SurfacePropertyMasks`
}
// Forward declare types
enum class RideEntryFlags;
enum class SurfacePropertyMasks;
//enum class FootpathEntryFlags;
// clang-format off
// Sets value to 'true_type' for the enum classes listed, 'false_type' otherwise
template <typename T>
struct is_openrct2_enum_class : std::bool_constant<
std::is_same<T, RideEntryFlags>::value ||
std::is_same<T, SurfacePropertyMasks>::value// ||
//std::is_same<T, FootpathEntryFlags>::value
>
{
};
// clang-format on
// First option: only define the bitwise operators when the types match
// Gives complicated looking compiler error when a type doesn't match
template <typename T>
inline constexpr typename std::enable_if_t<is_openrct2_enum_class<T>::value, T> operator|(T lhs, T rhs)
{
return static_cast<T>(static_cast<std::size_t>(lhs) | static_cast<std::size_t>(rhs));
}
template <typename T>
inline constexpr typename std::enable_if_t<is_openrct2_enum_class<T>::value, T&> operator|=(T & lhs, T rhs)
{
lhs = lhs | rhs;
return lhs;
}
// Second option: Always defines the function, and use static_assert to make sure the type match (much cleaner compilation error)
template <typename T>
inline constexpr T operator&(T lhs, T rhs)
{
static_assert(is_openrct2_enum_class<T>::value, "Type is not an openrct2 enum class");
return static_cast<T>(static_cast<std::size_t>(lhs) & static_cast<std::size_t>(rhs));
}
template <typename T>
inline constexpr T & operator&=(T & lhs, T rhs)
{
static_assert(is_openrct2_enum_class<T>::value, "Type is not an openrct2 enum class");
lhs = lhs & rhs;
return lhs;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment