Search code examples
c++arraysbitwise-operatorsstd-bitset

How to implement an array of bits in C++


I am trying to write a C++ template class which contains an array of bits (as a member variable). The size of the bit-array is known at compile time, so I'd really like it to be a std::bitset, but I'm having difficulty writing an operator[] function to set the bits.

For example, I'd like my class to start out something like this:

template<size_t N>
class bitvector
{
public:
    bool operator[](size_t i) const { return bits[i]; }
    bool& operator[](size_t i) { return bits[i]; }
private:
    std::bitset<N> bits;
};

The getter works okay. The problem is that the std::bitset::operator[] setter function returns a std::bitset::reference (not a bool&) which is itself templated. I'm not too experienced with templates, but the following attempt failed:

template<size_t K>
std::bitset<K>::reference operator[](size_t i) { return bits[i]; }

with the following error need 'typename' before 'std::bitset<K>::reference' because 'std::bitset<K>' is a dependent scope. I tried some googling, but to no avail.

Is std::bitset a suitable tool for this task? If so, how can I write the setter function? If not, what can I use instead? (I would still like it to be actually stored as bits, and std::vector<bool> doesn't seem quite right, as I want the array size to be strictly fixed at compile time).


Solution

  • You can just return a std::bitset<N>::reference as follows:

    template<size_t N>
    class bitvector
    {
    public:
        bool operator[](size_t i) const { return bits[i]; }
        typename std::bitset<N>::reference operator[](size_t i) { return bits[i]; }
    private:
        std::bitset<N> bits;
    };
    

    There's no need to have the additional template<size_t K> since you can still access the original template parameter N, and under no circumstances would you want the N and your K to be different.

    You need the typename before the function's return type to tell the compiler the ::reference is a type rather than a value.

    For example:

    struct Foo{
       typedef int reference;
    };
    
    struct Bar{
        static int reference;
    };
    

    Here Foo::reference is a type, but Bar::reference is a variable, without the typename before the return type the compiler will complain as it could be that std::bitset<N>::reference is a variable. (The compiler should have all the information it needs to work out that it isn't a value, but for some reason it is required anyway).