La même chose est faite dans std::vector<bool>
et std::bitset
dans la bibliothèque standard. Comme indiqué dans le , std::vector<bool>
il renvoie une classe proxy dont les opérateurs sont surchargés pour agir en tant qu'élément du vecteur.
Vous pourriez aussi le faire.
Pour un exemple convivial voir à nouveau l'reference pour une interface publique, il est quelque chose comme ceci:
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();
};
// ...
};
Pour mettre en œuvre cette classe, vous devez stocker un pointeur de membre à votre bloc de données réelles et un masque opérer avec.
Pour un exemple réel, dans les en-têtes g ++, recherchez la classe de membres std::vector<bool>
appelée std::vector<bool>::_Bit_reference
dans le fichier bits/stl_bvector.h
.
Pour clarifier l'OP avec un exemple:
Disons que vous avez une classe contenant 320 bools. Vous pouvez l'écrire comme suit:
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; } }
}
Vous souhaitez ajouter un opérateur []. Pour ajouter un const un est facile:
class boolcontainer {
uint32_t data[10];
public:
bool operator[](int i) const { return data[i/32] & (1 << (i%32)); }
}
pour avoir un non-const vous avez besoin de beaucoup plus. Vous devez d'abord créer une classe qui représente une référence à votre valeur. Vous devez avoir une sorte de pointeur vers où la valeur est stockée et (dans ce cas) vous avez besoin d'un masque de bits pour spécifier un bit concret. Pour être en mesure de gérer cela comme bool & vous devez ajouter certains opérateurs, à savoir la conversion bool et opérateur =:
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<
};
Notez que la struct ci-dessus se comporte comme un bool & - la lecture de celui-ci lit le valeur à partir du point de données représenté par le pointeur et le masque, et de même, en écrivant à lui écrase le bit à l'emplacement représenté. J'ai également écrit un constructeur qui initialise les membres.
Maintenant, tout ce dont vous avez besoin est que votre opérateur de boolcontainer [] doit renvoyer un objet de la classe ci-dessus:
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)); }
};
Et maintenant un peu de code pour le tester (imprime uniquement les 40 premières valeurs):
#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);
}
Et toutes les autres utilisations de l'opérateur d'indice vont kaboom! –
Ce n'est pas une bonne idée de surcharger un opérateur pour quelque chose d'autre que les types réguliers. – Rapptz
Pourquoi n'utiliserais-tu pas 'std :: bitset' au lieu d'en faire un? – chris