C ++ весь путь через эту функцию будет вызывать себя в макросе? - PullRequest
1 голос
/ 22 марта 2019

Эй, ребята, я написал макрос, чтобы легко определить операторы enum, и я получаю

предупреждение: весь путь через эту функцию будет вызываться сам

Я понимаю, что это означает, что функция рекурсивная, но где?

#define DEFINE_BITMASKENUM_OPERATORS(et, ut) \
    constexpr et operator &(const et a, const et b) noexcept { return (et(static_cast<ut>(a) & static_cast<ut>(b))); } \
    constexpr et operator |(const et a, const et b) noexcept { return (et(static_cast<ut>(a) | static_cast<ut>(b))); } \
    constexpr et operator ^(const et a, const et b) noexcept { return (et(static_cast<ut>(a) ^ static_cast<ut>(b))); } \
    constexpr et operator~(const et a) noexcept { return ~(a); } \
    inline et& operator&=(const et& a, const et b) noexcept {  return (reinterpret_cast<et&>((ut&)a &= (ut)b)); } \
    inline et& operator^=(const et& a, const et b) noexcept {  return (reinterpret_cast<et&>((ut&)a ^= (ut)b)); } \
    inline et& operator|=(const et& a, const et b) noexcept {  return (reinterpret_cast<et&>((ut&)a |= (ut)b)); }

et является типом enum и ut базовым типом. Это будет использовано так:

enum kRUNTIME_FLAGS : short16
{
    kRUNTIME_FLAGS_DEF                                                                          = 0b010,
    kRUNTIME_FLAGS_NO_RUNTIME_STATISTICS_RECORDING          = 0b0100,
    kRUNTIME_FLAGS_ENABLE_TERMINAL                          = 0b01000,
    kRUNTIME_FLAGS_ENABLE_EDIT_MODE                         = 0b010000,
    kRUNTIME_FLAGS_ALLOW_EDIT_MODE_SWITCH                   = 0b0100000,
    kRUNTIME_FLAGS_STOP                                     = 0b01000000,
    kRUNTIME_FLAGS_ALLOW_AUTO_STRIDE_FLUSH                  = 0b010000000
};
DEFINE_BITMASKENUM_OPERATORS(kRUNTIME_FLAGS, short16)

но где функция вызывает себя и как это исправить? Это исправлено сейчас, для всех, кому нужно что-то подобное, эта шаблонная версия должна работать, я думаю:

template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
constexpr ENUM operator&(const  ENUM a, const  ENUM b) noexcept { return (ENUM(static_cast<ENUM_TYPE>(a) & static_cast<ENUM_TYPE>(b))); }
template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
constexpr ENUM operator|(const  ENUM a, const  ENUM b) noexcept { return (ENUM(static_cast<ENUM_TYPE>(a) | static_cast<ENUM_TYPE>(b))); }
template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
constexpr ENUM operator^(const  ENUM a, const  ENUM b) noexcept { return (ENUM(static_cast<ENUM_TYPE>(a) ^ static_cast<ENUM_TYPE>(b))); }
template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
constexpr ENUM operator~(const ENUM a) noexcept { return ENUM(~static_cast<ENUM_TYPE>(a)); }
template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
inline ENUM& operator&=(const ENUM& a, const ENUM b) noexcept { return (reinterpret_cast<ENUM&>((ENUM_TYPE&)a &= (ENUM_TYPE)b)); }
template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
inline ENUM& operator^=(const ENUM& a, const ENUM b) noexcept { return (reinterpret_cast<ENUM&>((ENUM_TYPE&)a ^= (ENUM_TYPE)b)); }
template<typename ENUM, typename  ENUM_TYPE = typename std::underlying_type<ENUM>::type>
inline ENUM& operator|=(const ENUM& a, const ENUM b) noexcept { return (reinterpret_cast<ENUM&>((ENUM_TYPE&)a |= (ENUM_TYPE)b)); }

1 Ответ

1 голос
/ 22 марта 2019

Изменение:

constexpr et operator~(const et a) noexcept { return ~(a); }

на

constexpr et operator~(const et a) noexcept { return et(~static_cast<ut>(a)); }

, и оно должно компилироваться без предупреждений.

#include <cstdint>
#define DEFINE_BITMASKENUM_OPERATORS(et, ut) \
    constexpr et operator &(const et a, const et b) noexcept { return (et(static_cast<ut>(a) & static_cast<ut>(b))); } \
    constexpr et operator |(const et a, const et b) noexcept { return (et(static_cast<ut>(a) | static_cast<ut>(b))); } \
    constexpr et operator ^(const et a, const et b) noexcept { return (et(static_cast<ut>(a) ^ static_cast<ut>(b))); } \
    constexpr et operator~(const et a) noexcept { return et(~static_cast<ut>(a)); } \
    inline et& operator&=(const et& a, const et b) noexcept {  return (reinterpret_cast<et&>((ut&)a &= (ut)b)); } \
    inline et& operator^=(const et& a, const et b) noexcept {  return (reinterpret_cast<et&>((ut&)a ^= (ut)b)); } \
    inline et& operator|=(const et& a, const et b) noexcept {  return (reinterpret_cast<et&>((ut&)a |= (ut)b)); }

enum kRUNTIME_FLAGS : int16_t
{
    kRUNTIME_FLAGS_DEF                                                                          = 0b010,
    kRUNTIME_FLAGS_NO_RUNTIME_STATISTICS_RECORDING          = 0b0100,
    kRUNTIME_FLAGS_ENABLE_TERMINAL                          = 0b01000,
    kRUNTIME_FLAGS_ENABLE_EDIT_MODE                         = 0b010000,
    kRUNTIME_FLAGS_ALLOW_EDIT_MODE_SWITCH                   = 0b0100000,
    kRUNTIME_FLAGS_STOP                                     = 0b01000000,
    kRUNTIME_FLAGS_ALLOW_AUTO_STRIDE_FLUSH                  = 0b010000000
};
DEFINE_BITMASKENUM_OPERATORS(kRUNTIME_FLAGS, int16_t)

https://gcc.godbolt.org/z/ORF5iX

...