Q:

What is the logic behind binary comparison between elements and number of elements in finding a subset?

Consider the following problem from a book (https://cses.fi/book/book.pdf): 
"We first consider the problem of generating all subsets of a set of n elements. For example, the subsets of {0,1,2} are φ, {0}, {1}, {2}, {0,1}, {0,2}, {1,2} and {0,1,2}. There are two common methods to generate subsets: we can either perform a recursive search or exploit the bit representation of integers."
Solution number 2 in the book (page 48, PDF page 58) is the following:
for (int b = 0; b < (1<<n); b++) {
    vector<int> subset;
    for (int i = 0; i < n; i++) {
        if (b&(1<<i)) subset.push_back(i);
    }
}

My question is: why does the (b&(1<<i)) comparison work? Just what is it doing in the background? I've tried it out by hand for the subsets of {0, 1}, and it works flawlessly, but just why do comparisons between them work? b is a counter for the number of elements and (1<<i), from my understanding is basically equivalent to 2i. Why does it all work though? It seems like magic. 
PS. I know the book is a bad C++ reference, I'm reading it more so for algorithm explanations.

A:

Assign each element in the set a different power of two (1, 2, 4, 8, etc.) as an ID.  Each subset is a combination of various elements in the set, which can be represented by combinations of the IDs.  Adding up the IDs in a subset will give a unique number.
This can also be worked in reverse:  every number from 0 to 2n-1 will represent a subset of the set, where 0 represents the empty set (since no elements are present) and 2n-1 is the subset with all elements in it.  Incrementing a number from 0 to 2n-1 will enumerate all possible subsets.
The 1 << i corresponds to one of these IDs, b & (1 << i) will check the current subset to see if element i belongs in it.

A:

Think of the ints as strings of bits instead of numerical values
Here, each bit in b represents whether the corresponding element is in the subset or not. Looping from 0 to 2n iterates over all possible states of n bits since each state is an integer between 0 and 2n. Therefore, the values of b will represent all possible subsets.
In order to convert a value of b to the corresponding subset, we loop over each of the elements and test whether the element is in the subset. We add an element to the vector if the corresponding bit is set in b. To test if the ith bit is set in b, we compute b & (1 << i).
& is bitwise AND, so a bit in the result will be set only if that bit is set in both the operands. 1 << i is a bitmask with the ith bit set and all other bits not set. When we compute the bitwise AND of b and 1 << i, all of the bits other than the ith bits won't be set because the corresponding bit isn't set in the bitmask. The ith bit will be set only if the ith bit in b is set. So we will get something other than 0 if the ith bit is set and 0 otherwise. Since converting from int to bool tests if the value isn't 0, the body of the if statement will execute if the ith bit of b is set.

