How it works...

If you've ever worked with C or C-like APIs, chances are you either wrote or at least have seen code that manipulates bits to define styles, options, or other kinds of values. This usually involves operations, such as:

  • Defining the bit flags; these can be enumerations, static constants in a class, or macros introduced with #define in the C style. Usually, there is a flag representing no value (style, option, and so on). Since these are supposed to be bit flags, their values are powers of 2.
  • Adding and removing flags from the set (that is, a numerical value). Adding a bit flag is done with the bit-or operator (value |= FLAG) and removing a bit flag is done with the bit-and operator, with the negated flag (value &= ~FLAG).
  • Testing whether a flag is added to the set (value & FLAG == FLAG).
  • Calling functions with the flags as an argument.

The following shows a simple example of flags defining the border style of a control that can have a border on the left, right, top, or bottom side, or any combination of these, including no border:

    #define BORDER_NONE   0x00
#define BORDER_LEFT 0x01
#define BORDER_TOP 0x02
#define BORDER_RIGHT 0x04
#define BORDER_BOTTOM 0x08

void apply_style(unsigned int const style)
{
if (style & BORDER_BOTTOM) { /* do something */ }
}

// initialize with no flags
unsigned int style = BORDER_NONE;
// set a flag
style = BORDER_BOTTOM;
// add more flags
style |= BORDER_LEFT | BORDER_RIGHT | BORDER_TOP;
// remove some flags
style &= ~BORDER_LEFT;
style &= ~BORDER_RIGHT;
// test if a flag is set
if ((style & BORDER_BOTTOM) == BORDER_BOTTOM) {}
// pass the flags as argument to a function
apply_style(style);

The standard std::bitset class is intended as a C++ alternative to this C-like working style with sets of bits. It enables us to write more robust and safer code because it abstracts the bit operations with member functions, though we still need to identify what each bit in the set is representing:

  • Adding and removing flags is done with the set() and reset() methods, which set the value of a bit indicated by its position to 1 or 0 (or true and false); alternatively, we can use the index operator for the same purpose.
  • Testing if a bit is set is done with the test() method.
  • Conversion from an integer or a string is done through the constructor, and conversion to an integer or string is done with member functions so that the values from bitsets can be used where integers are expected (such as arguments to functions).

In addition to these mentioned operations, the bitset class has additional methods for performing bitwise operations on bits, shifting, testing, and others that have been shown in the previous section.

Conceptually, std::bitset is a representation of a numerical value that enables you to access and modify individual bits. Internally, however, a bitset has an array of integer values on which it performs bit operations. The size of a bitset is not limited to the size of a numerical type; it can be anything, except that it is a compile-time constant.

The example with the control border styles from the previous section can be written using std::bitset in the following manner:

    struct border_flags
{
static const int left = 0;
static const int top = 1;
static const int right = 2;
static const int bottom = 3;
};

// initialize with no flags
std::bitset<4> style;
// set a flag
style.set(border_flags::bottom);
// set more flags
style
.set(border_flags::left)
.set(border_flags::top)
.set(border_flags::right);
// remove some flags
style[border_flags::left] = 0;
style.reset(border_flags::right);
// test if a flag is set
if (style.test(border_flags::bottom)) {}
// pass the flags as argument to a function
apply_style(style.to_ulong());
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset