Re[3]: implicit operator bool
От: andrey.desman  
Дата: 22.03.24 22:21
Оценка:
Здравствуйте, Marty, Вы писали:

M>А вот это видимо то, почему я сразу так не сделал, и просто забыл

M>А есть какие-нибудь варианты?

Вариант через класс и на шаблонах, а не на макросах.

Я делал так

#pragma once

#include <initializer_list>
#include <type_traits>

namespace foo
{
  template<typename BitEnum>
  class Flags;
}

/// A class that handles bitmasked enum (preferrably enum class) in a way that it keeps type safety, but
/// provides simplicity and convenience of raw integers.
///
/// \details The enum must consist from bit-masked values, e.g.
/// \code{.cpp}
/// enum class SomeFlags
/// {
///   Flag0 = 0b0001,
///   Flag1 = 0b0010,
///   Flag2 = 0b0100,
///   Flag3 = 0b1000,
/// };
/// \endcode
/// Although multi-bit enum members are allowed and just represent shorthand for common combinations, a care
/// should be taken not to treat them as individual values.
template<typename BitEnum>
class foo::Flags
{
  using UnderlyingType = std::underlying_type_t<BitEnum>;

  template<typename T1, typename... REST>
  constexpr UnderlyingType makeMask(T1 first, REST... rest) const
  {
    static_assert((std::is_same_v<T1, BitEnum> && ... && std::is_same_v<REST, BitEnum>), "Arguments must be of enum type");
    return (UnderlyingType(first) | ... | UnderlyingType(rest));
  }

public:
  constexpr Flags() = default;

  /// Constructs a flag set by combining/disjuncting its' arguments.
  template<typename T1, typename... REST>
  constexpr Flags(T1 first, REST... rest)
    : m_flags(makeMask(first, rest...))
  {
  }

  /// Constructs a flag set by combining/disjuncting flags in passed initializer list.
  constexpr Flags(std::initializer_list<BitEnum> list)
  {
    for (auto flag : list)
      m_flags |= UnderlyingType(flag);
  }

  /// Tells whether any of specified flags are set.
  template<typename T1, typename... REST>
  constexpr bool any(T1 first, REST... rest) const
  {
    return bool(m_flags & makeMask(first, rest...));
  }

  /// Tells whether all of specified flags are set.
  template<typename T1, typename... REST>
  constexpr bool all(T1 first, REST... rest) const
  {
    const auto mask = makeMask(first, rest...);
    return (m_flags & mask) == mask;
  }

  /// Tells whether none of specified flags are set.
  template<typename T1, typename... REST>
  constexpr bool none(T1 first, REST... rest) const
  {
    const auto mask = makeMask(first, rest...);
    return !(m_flags & mask);
  }

  /// Sets specified flags.
  template<typename T1, typename... REST>
  constexpr Flags& set(T1 first, REST... rest)
  {
    m_flags |= makeMask(first, rest...);
    return *this;
  }

  /// Unsets specified flags.
  template<typename T1, typename... REST>
  constexpr Flags& reset(T1 first, REST... rest)
  {
    m_flags &= ~makeMask(first, rest...);
    return *this;
  }

  /// Unsets all flags.
  void clear()
  {
    m_flags = 0;
  }

  constexpr explicit operator bool() const
  {
    return m_flags != 0;
  }

  constexpr bool operator!() const
  {
    return m_flags == 0;
  }

  constexpr operator BitEnum() const
  {
    return BitEnum(m_flags);
  }

  constexpr Flags operator&(Flags r)
  {
    return Flags{BitEnum(m_flags & r.m_flags)};
  }

  constexpr friend Flags operator&(BitEnum l, Flags r)
  {
    return Flags(l) & r;
  }

  constexpr Flags operator|(Flags r)
  {
    return Flags{BitEnum(m_flags | r.m_flags)};
  }

  constexpr friend Flags operator|(BitEnum l, Flags r)
  {
    return Flags(l) | r;
  }

  constexpr Flags& operator&=(Flags r)
  {
    m_flags &= r.m_flags;
    return *this;
  }

  constexpr Flags& operator|=(Flags r)
  {
    m_flags |= r.m_flags;
    return *this;
  }

private:
  UnderlyingType m_flags = 0;
};
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.