Le masquage et le décalage vont se produire indépendamment du sucre syntaxique que vous ajoutez. Si vous voulez rendre les choses vraiment faciles à utiliser, mais un peu plus difficile à faire en premier lieu, vous pouvez utiliser une classe, avec un peu de code macro/template pour faciliter la définition de nouvelles classes:
template<bool> struct CompileTimeAssert;
template<> struct CompileTimeAssert<true> { };
#define ASSERT(check) if (!check) throw exception("Assertion Failure" #check)
#define ADDBITVALUE(backingField, backingFieldType, fieldName, offset, size) \
public: \
static const unsigned int fieldName##Offset = offset; \
static const backingFieldType fieldName##Mask = CalculateMask<offset, size, backingFieldType>::Value; \
public: \
void Set##fieldName(backingFieldType value) \
{\
ASSERT(("Value too large for field.", (value & (fieldName##Mask >> fieldName##Offset)) == value));\
backingField |= value << fieldName##Offset;\
}\
backingFieldType Get##fieldName() const\
{\
return (backingField & fieldName##Mask) >> fieldName##Offset;\
}\
private:
#define ADDSPANNEDVALUE(backingField1, backingField1Type, backingField2, backingField2Type, fieldName, offset1, size1, offset2, size2)\
ADDBITVALUE(backingField1, backingField1Type, fieldName##internal1, offset1, size1)\
ADDBITVALUE(backingField2, backingField2Type, fieldName##internal2, offset2, size2)\
public: \
void Set##fieldName(backingField1Type value) \
{\
backingField1Type value1 = value << (sizeof(backingField1Type)*8-size1);\
value1 = value1 >> (sizeof(backingField1Type)*8-size1);\
Set##fieldName##internal1(value1);\
Set##fieldName##internal2(value >> size1);\
}\
backingField1Type Get##fieldName() const\
{\
return Get##fieldName##internal1() | (Get##fieldName##internal2() << size1);\
}\
private:
template <unsigned int Offset, int Size, typename T>
struct CalculateMask
{
CompileTimeAssert<(Size > 0)> Object;
static const T Value = (T)((1 << Offset) | CalculateMask<Offset + 1, Size - 1, T>::Value);
};
template <unsigned int Offset, typename T>
struct CalculateMask<Offset, 0, T>
{
CompileTimeAssert<(Offset <= sizeof(T) * 8)> Object;
static const T Value = 0;
};
Définissez ensuite votre classe comme ceci:
class BitGroup
{
unsigned short Values;
unsigned short Values2;
ADDBITVALUE(Values, unsigned short, Field1, 0, 12);
ADDSPANNEDVALUE(Values, unsigned short, Values2, unsigned short, Field2, 12, 4, 0, 2);
ADDBITVALUE(Values2, unsigned short, Field3, 2, 14);
public:
BitGroup() : Values(0), Values2(0) {}
};
Utilisation:
BitGroup bg;
bg.SetField1(15);
cout << bg.GetField1();
bg.SetField2(63);
cout << bg.GetField1();
Vous obtiendrez une compilation si vos champs affirment ne relèvent pas de la plage des champs d'appui. Il n'y a pas de vérification que les champs ne se chevauchent pas, donc vous devriez faire attention à cela.
Il est tentant d'utiliser des champs de bits, mais ils ne sont pas portables, ce qui peut souvent être le dealbreaker. –
c'est ce que je cherche, bien que, comme Brian l'a dit, pas portable, et ne fonctionne pas avec mon OS –