C ++ 11检查标志的方法

时间:2014-10-31 00:09:26

标签: c++ c++11

典型的C风格方法:

#define LOG_ERRORS            1  // 2^0, bit 0
#define LOG_WARNINGS          2  // 2^1, bit 1
#define LOG_NOTICES           4  // 2^2, bit 2
#define LOG_INCOMING          8  // 2^3, bit 3
#define LOG_OUTGOING         16  // 2^4, bit 4
#define LOG_LOOPBACK         32  // and so on...

// Only 6 flags/bits used, so a char is fine
unsigned char flags;

// initialising the flags
flags = LOG_ERRORS;

//initialising to multiple values with OR (|)
flags = LOG_ERRORS | LOG_WARNINGS | LOG_INCOMING;
// sets to 1 + 2 + 8 i.e. bits 0, 1 and 3

// testing for a flag
// AND with the bitmask before testing with ==
if ((flags & LOG_WARNINGS) == LOG_WARNINGS)
   ...

// testing for multiple flags
// as above, OR the bitmasks
if ((flags & (LOG_INCOMING | LOG_OUTGOING))
         == (LOG_INCOMING | LOG_OUTGOING))
   ...

在C ++ 11中是否有更好的方法,它保留了旧的C风格界面(LOG_INCOMING | LOG_OUTGOING)?即如何摆脱“丑陋”的方式来检查哪些位被设置?

我一直在关注std::bitset,但后者仅测试位置查询(例如,它可以测试是否设置了第3位)并且无法测试类似的内容:

  LOG_INCOMING | LOG_OUTGOING

3 个答案:

答案 0 :(得分:4)

我会将您的宏替换为static const int s(嗯,或者使用显式值的enum),但除此之外您的实现就可以了。

你不应该仅仅因为可以用一些新的模板怪物替换好的,可靠的,健壮的,清晰的,自我记录的,简洁的,可靠的代码。

您的代码足够现代,这种模式仍在使用中。

答案 1 :(得分:3)

我认为0x / 1y功能的代码性能没有任何问题。如果它已经过充分测试,您可能希望避免重写(特别是如果现有代码依赖于它)。

如果只想了解如何使用功能的一些想法,可以采取一些不同的方法。

... constexpr

constexpr uint8_t bit(const uint8_t n) {
  return 1 << n;
}

constexpr static const uint8_t LOG_ERRORS =   bit(0);
constexpr static const uint8_t LOG_WARNINGS = bit(1);

if (flags & (LOG_ERROR | LOG_WARNINGS))

二进制文字......

static const uint8_t LOG_ERRORS =   0b00000001;
static const uint8_t LOG_WARNINGS = 0b00000010;

if (flags & (LOG_ERRORS | LOG_WARNINGS))

可变参数模板......

template<typename T, typename... Ts>
T bit_or(T t, Ts... ts) {
  return t | bit_or(ts...);
}

template<typename T>
T bit_or(T t) {
  return t;
}

template<typename T, typename... Ts>
bool any_set(T t, Ts... ts) {
  return static_cast<bool>(t & (bit_or(ts...)));
}

constexpr uint8_t bit(const uint8_t n) {
  return 1 << n;
}

constexpr static const uint8_t LOG_ERRORS   = bit(0);
constexpr static const uint8_t LOG_WARNINGS = bit(1);

if (any_set(flags, LOG_ERRORS, LOG_WARNINGS))

我个人的偏好是避免std::bitset,因为它不能在布尔上下文中直接评估。但是,我可能会考虑在类中包装flags,并使用enum class : uint8_t作为类型安全的标志。该类可能类似于Java的EnumSet。您可以轻松地重置按位操作(&|^~等等...),以保留C接口。

答案 2 :(得分:1)

bitset,其中包括set N位到true;它还有一些转换为unsignedstring的方法(C ++字符串,而不仅仅是char C风格的空终止序列)

除此之外,我不认为有更多的C ++ - 这样做的方法,但我可能会采用类似于刚刚描述的Orness中Lightness Races的方法,保守并且不添加你不需要的开销。