The flagword parameterized class is used to pack a bunch of options into
a single value.
There are three ways to represent such a set of flags: (a) as bits within some flavor of
integer; (b) as a bit vector of arbitrary length; and (c) as a list or spare array. This class
implements type (a), which are quite common in the Win32 API, so existing needs easily meet
the restrictions of this type (namely, flags are constants that are powers of two, and at most
32 flags can be packed into one set), and it is trivial to extract the native format expected by
the Win32 API calls.
Explaination by Example
Start with an enumerated type specifying flags that are powers of two.
The idea is that you can logically OR multiple flags together to create a set of flags. For example,
red|green|blackwill have a unique bit combination that distinguishes it from any
other set of colors. The problem is that OR-ing the flags together will produce a result of
type int, not of type color. This compromises the compile-time
type checking of the system.
void selection (int mycolors);
You can't declare the function to take a color, because then you could not
call the function with the result of the logical-OR. You could define your own operator|
to operate on this type, but you would have to do so for every such type. This is a real possibility, though.
The flagword class creates a type-checked way of handling these flags, along with many
other features.
typedef classics::flagword<color> colorflags;
Now you can declare the function as
void selection (colorflags mycolors);
and the compiler will perform strong type checking on this argument, and it is clear to the
reader that a set of colors, not (just) a single color, is expected.
You can pass a single color enumeration constant to the function because there is an
implicit converstion from color to colorflags.
selection (blue);
For passing multiple flags, it's a little harder than the ideal (an operator| taking color for both
arguments and returning a flagword, generated automatically when the template is instantiated) because
the operator| would exist in the classics namespace and not be found when applying the operator between
two arguments of types that are in a different namespace. To make matters worse, the compiler chokes
when you try a using declaration or the qualified function name (classics::operator|) syntax.
So, the operator| is provided for colorflags only, not for the underlying color enumeration. You can
add the function manually if you want, but in general all the operations are provided for flagword types
and rely on conversion from the underlying enumeration type in mixed expressions
So, if you're not totally lost by this point, the way to join multiple flags together is to
cast one of them manually.
selection (colorflags(red)|green|black);
Alternativly, you could use a variable of type colorflags.
As you see from the example and the list below, the flagword is fully expressive. But you don't know the half of it yet.
Logical Flag Operations
|, |=
logical bit-wise OR.
&, &=
logical bit-wise AND.
^, ^=
meaning not yet defined
prefix ~
Reverse all bits
True Negative Flags
In a traditional int packed with flags, the presence of a bit means that the flag is set. Does
the absence of a bit mean that the flag is definitly unset, or simply unspecified? A number of
data structures in the Win32 API run into this issue, and solve it by using a pair of words: One
states which flags are meaningful, and the other gives the meanings for those selected flags. The
flagword class models this behavior directly, and in fact implements it in this way so it's trivial
to extract the raw data for use in Win32 API functions or other legacy code.
The constructor can take two arguments. The first is the bit image for the data; which flags are
set. The second is the bit image for the validity mask; which flags are meaningful in the first argument.