Ich hab das schon als Inlinefunktion gemacht.. das löst das jetzige Problem nicht. In gewissen Situation haben Bitfields ihre Daseinsberechtigung, da bin ich stark dafür, unabhäängig davon, was andere da sagen. Ich vermute, dass andere Leute in iherer Hardwareumgebung nur selten mit in Hardware implementierten Bitfeldern zu tun haben. Ich weiß nicht, warum man das dann nicht auch tatsächlich in Software abbilden sollen können dürfen könnte.
Das finde ich das gleiche Niveau, wie wenn jemand sagt, dass man
goto nicht verwenden darf.
Prinzipiell könnte man die Warnung [-Wconversion] auch einfach abschalten, aber ich finde die Warnung gar nicht so dumm. So entscheidet man sich immer explizit, Bits wegzuwerfen und die Typgröße zu verringern.
Aber da ihr nun alle auf den Bitfields rumhackt und es nicht um das eigentliche Problem geht, habe ich mitlerweile eine Lösung gefunden :-)
Grundproblem war/ist, das Template-Parameter-Deduction nur für Funktionsaufrufe, nicht aber für Klassen-Templates funktioniert :!: [/u]
Die Lösung sieht nun so aus:
Code: Alles auswählen
template<unsigned int N, typename T> union NBitValueUnion
{
static_assert((sizeof(T)*8) > N, "Komische Bitanzahl");
private:
const T Data;
public:
struct
{
const T Value : N;
const T : (sizeof(T)*8-N);
};
NBitValueUnion(const T& _Data): Data(_Data) {}
};
template<unsigned int N, typename T> const NBitValueUnion<N, T> NBitValue(const T& _Data)
{ return NBitValueUnion<N, T>(_Data); }
Damit kann ich jetzt tatsächlich gemütlich:
schreiben und alles ist gut. Um das
.Value komme ich leider nicht drum rum.
Ich habe auch
Code: Alles auswählen
template<unsigned int N, typename T> const auto NBitValue2(const T& _Data) ->decltype(NBitValueUnion<N, T>::Value)
{ return NBitValueUnion<N, T>(_Data).Value; }
probiert. Leider wird im
auto die Typbreite irgnoriert [könnte man fast als compiler bug sehen], sodass [-Wconversion] wieder aufploppt.
Das Gute ist jetzt, dass man zur Laufzeit nun checken könnte, ob bei der Zuweisung Informationen verloren gehen (Bitfield-Überlauf). Der Compiler macht das für Compile-Time-Konstanten auch schon.. zum debuggen nicht schlecht. Ich weiß, das ginge mit der üblichen Bitschieberei auch.
Und hier muss ich nochmal widersprechen: eine Inline-Funktion ist anfällig für Fehler. Gehen wir nochmal vom Beispiel-Bitfeld aus.
Code: Alles auswählen
union SBitfield
{
unsigned int Data;
struct
{
unsigned int a : 4;
unsigned int b : 4;
unsigned int : 24;
};
};
Angenommen du hättest diese Definition nicht direkt vor Augen, würde es dir mitten im Code auffallen, dass du mit
Code: Alles auswählen
Bitfield.Data = SetBitField<2 /*Start*/, 4 /*Width*/>(Bitfield.Data, NewContent);
keines der in Hardware real existierenden Bitfelder triffst? :o
Nein, man übersieht es. Der Code compiliert und er läuft auch. Nur die Hardware verhält sich dann dumm.
Mit
Code: Alles auswählen
Bitfield.a = NewContent;
//bzw
Bitfield.a = NBitValue<4>(NewContent);
ist hingegen absolut sichergestellt, dass man keinen Fehler macht.
Und der Assembler-Code ist der selbe.