Overloading the index operator for non-array elements
I wrote a template class to store multiple bools in integers. Right now setting and getting each bool is done with explicit functions
bool isBitSet(int index)
{
return static_cast<bool>((block_ >> index) % 2)
}
void setBitOn(int index)
{
block_ |= 1 << index;
}
I believe the following will work for getting the value, but how do I set it up to work since we can't directly return a link for a bit?
const bool operator [] (int index) const
{
return static_cast<bool>((block_ >> index) % 2);
}
source to share
The same is done in std::vector<bool>
and std::bitset
in the standard library. As referenced , std::vector<bool>
it returns a proxy class that has its operators overloaded to act as a vector element.
You could do that too.
For a handy example, look again at the reference for the public interface, it goes something like this:
template <class Allocator>
class vector<bool, Allocator> {
// ...
public:
class reference {
friend class vector;
reference();
public:
~reference();
operator bool() const;
reference& operator=(bool x);
reference& operator=(const reference&);
void flip();
};
// ...
};
To implement this class, you must store a pointer to your actual data block and mask to work with.
For a real-world example, in the g ++ headers, find the member class std::vector<bool>
named std::vector<bool>::_Bit_reference
in the file bits/stl_bvector.h
.
To clarify the OP with an example:
Let's say you have a class containing 320 points. You could write it like:
class boolcontainer {
uint32_t data[10];
public:
//default ctor. to initialize the elements with zeros
boolcontainer() { for (int i = 0; i < 10; ++i) { data[i] = 0; } }
}
You want to add the [] operator. To add a constant, simply:
class boolcontainer {
uint32_t data[10];
public:
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
}
have a non-const one that you need a lot more. First, you need to create a class that represents a reference to your value. You must have some sort of pointer to where the value is stored and (in this case) you need a bitmask to indicate one particular bit. To be able to handle this as a bool & you need to add some operators, namely the conversion to bool and operator =:
class reference {
uint32_t *dataptr;
uint32_t mask;
public:
//constructor just initializing members
reference(uint32_t *dataptr_, uint32_t mask_) : dataptr(dataptr_), mask(mask_) {}
//conversion to bool
operator bool() const {
//just like in the getter, but the bitmask is stored now locally
return *dataptr & mask;
}
//sets one single bit represented by mask to b
reference& operator=(bool b) {
if (b) {
*dataptr |= mask;
} else {
*dataptr &= ~mask;
}
return *this;
}
//TODO copy ctor., operator==, operator<
};
Note that the above structure will behave like a bool & - reading from it reads the value from the data point represented by the pointer and mask, and likewise, writing to it overwrites the bit at the presented location. I also wrote a constructor that initializes the members.
Now all you need is that your boolcontainer [] statement should return an object of the class above:
class boolcontainer {
uint32_t data[10];
public:
boolcontainer() { for (int i = 0; i < 10; ++i) { data[i] = 0; } }
class reference {
... //see above
}
//keep the const version for efficiency
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
//non-const version returns our reference object.
reference operator[](int i) { return reference(&data[i/32], 1 << (i%32)); }
};
And now some code to test it (only prints the first 40 values):
#include <iostream>
#include "boolcontainer.h"
void printboolcontainer(const boolcontainer &bc)
{
//note that this is the constant version
for (int i = 0; i < 40; ++i) {
std::cout << bc[i];
}
std::cout << std::endl;
}
int main()
{
boolcontainer bc;
printboolcontainer(bc);
bc[0] = true;
bc[3] = true;
bc[39] = true;
printboolcontainer(bc);
}
source to share