Frage
Ich habe versucht, eine Funktion zu schreiben, die eine Ganzzahl mit nur dem höchsten Bit des Eingangssatzes unter Verwendung eines C ++ 0x ConstExpr zurückgibt.
constexpr inline uint64_t
get_highest_bit(uint64_t p)
{
return
(p|=(p>>1)),
(p|=(p>>2)),
(p|=(p>>4)),
(p|=(p>>8)),
(p|=(p>>16)),
(p|=(p>>32)),
(p-(p>>1));
}
Dies ergibt einen Kompilierungszeitausfall mit GCC 4.6.1.
error: expression ‘(p <unknown operator> ((p >> 1) | p))’ is not a constant-expression
Beachten Sie, dass es ohne das Keyword von Contexpr funktioniert.
Meine Fragen sind:
Warum geht das nicht? Ich kann sehen, dass Operator | = kein Contexpr ist, aber ist es für eingebaute Typen von Bedeutung?
Gibt es eine einfache Möglichkeit, diese Funktion als Contexpr zu schreiben? Ich möchte, dass es zur Laufzeit angemessen ist, und es ist mir ein wenig um die Lesbarkeit.
Lösung
(Nicht auf GCC getestet, weil ich nicht 4.6 habe, aber ich habe überprüft, ob der Algorithmus korrekt ist.)
Benutzen constexpr
Sie dürfen keine Aufgaben haben. Deshalb muss man oft einschreiben funktional Form mit Rekursion:
#include <cstdint>
#include <climits>
constexpr inline uint64_t highestBit(uint64_t p, int n = 1) {
return n < sizeof(p)*CHAR_BIT ? highestBit(p | p >> n, n * 2) : p - (p >> 1);
}
int main() {
static_assert(highestBit(7) == 4);
static_assert(highestBit(5) == 4);
static_assert(highestBit(0x381283) == 0x200000);
return 0;
}
Sie können C ++ 0x § [expr.const]/2 überprüfen, um festzustellen, welche Ausdrücke in a nicht verwendet werden können constexpr
Funktion. Insbesondere ist das zweite zu letztes Element "eine Zuordnung oder eine zusammengesetzte Zuordnung".
Andere Tipps
constexpr inline uint64_t highestBit(uint64_t p)
{
return (p & (p-1))? highestBit(p & (p-1)): p;
}
Jedes Rekursionsniveau löscht das gesetzte rechts rechtliche Bit, wenn das letzte Bit gelöscht wird, nur das höchste Bit blieb, sodass es zurückgegeben wird.