Sto cercando di fare una funzione constexpr
che converte una stringa UUID come "f6ece560-cc3b-459a-87f1-22331582216e"
ad una classe qualcosa di simile:costante parametro stringa espressione in funzione 11 constexpr C++
class UUID {
public:
explicit UUID(uint8_t bytes[]); // Must be 16 byte array.
Questo è quello che ho ottenuto finora:
// Compile time hex conversion of a single character into a nibble (half-byte).
constexpr uint8_t hexToNibble(char a)
{
// Does not work:
// static_assert(a >= '0' && a <= '9' || a >= 'a' && a <= 'f' || a >= 'A' && a <= 'F', "Invalid hex character");
return a >= '0' && a <= '9' ? (a - '0') :
a >= 'a' && a <= 'f' ? (a - 'a' + 10) :
a >= 'A' && a <= 'F' ? (a - 'A' + 10) : 0;
}
// Compile time hex conversion of two characters into a byte.
constexpr uint8_t hexToByte(char a, char b)
{
return (hexToNibble(a) << 4) + hexToNibble(b);
}
// Compile time string length.
constexpr int strlenConst(const char* str)
{
return *str ? 1 + strlenConst(str + 1) : 0;
}
// Convert a UUID string to an array of bytes.
// Example: "f6ece560-cc3b-459a-87f1-22331582216e".
constexpr std::array<uint8_t, 16> UUIDFromString(const char* str)
{
// This does not work:
// static_assert(strlenConst(str) == 36, "Invalid GUID length");
return std::array<uint8_t, 16>{
hexToByte(str[0], str[1]),
hexToByte(str[2], str[3]),
hexToByte(str[4], str[5]),
hexToByte(str[6], str[7]),
hexToByte(str[9], str[10]),
hexToByte(str[11], str[12]),
hexToByte(str[14], str[15]),
hexToByte(str[16], str[17]),
hexToByte(str[19], str[20]),
hexToByte(str[21], str[22]),
hexToByte(str[24], str[25]),
hexToByte(str[26], str[27]),
hexToByte(str[28], str[29]),
hexToByte(str[30], str[31]),
hexToByte(str[32], str[33]),
hexToByte(str[34], str[35]),
};
}
#define MAKE_UUID(var, str) \
static_assert(strlenConst(str) == 36, "Invalid GUID length for " #var); \
const UUID var(UUIDFromString(str).data());
// Works but doesn't check string length.
const UUID UUID_1(UUIDFromString("f6ece560-cc3b-459a-87f1-22331582216e").data());
// Checks string length but uses an ugly macro.
MAKE_UUID(UUID_2, "f6ece560-cc3b-459a-87f1-22331582216e")
Come potete vedere c'è un problema - a quanto pare è impossibile avere parametri di funzionalità che sono espressioni costanti in funzione constexpr, quindi non è possibile fare static_assert
s sui parametri, anche se il valore che w come passato era un'espressione costante.
Quindi ho fatto ricorso a una macro per controllare la lunghezza della stringa e ho rinunciato a controllare i caratteri.
C'è un modo per aggirare questo? Inoltre, come posso garantire che questa funzione venga effettivamente valutata al momento della compilazione?
Modifica: Questo non è lo stesso di C++11 - static_assert within constexpr function? - o almeno le stesse risposte non funzionano - vedere i commenti di seguito.
Modifica 2: la risposta eccellente di Shafik funziona per il problema delle dimensioni, ma non per controllare i caratteri esadecimali. Per quanto mi riguarda posso dire che è impossibile - anche se si utilizza questo ...
// Compile time hex conversion of a single character into a nibble (half-byte).
template<char a>
constexpr uint8_t hexToNibble()
{
static_assert(a >= '0' && a <= '9' || a >= 'a' && a <= 'f' || a >= 'A' && a <= 'F', "Invalid hex character");
return a >= '0' && a <= '9' ? (a - '0') :
a >= 'a' && a <= 'f' ? (a - 'a' + 10) :
a >= 'A' && a <= 'F' ? (a - 'A' + 10) : 0;
}
// Compile time hex conversion of two characters into a byte.
template<char a, char b>
constexpr uint8_t hexToByte()
{
return (hexToNibble<a>() << 4) + hexToNibble<b>();
}
Questo non funziona:
// Convert a UUID string to an array of bytes.
// Example: "f6ece560-cc3b-459a-87f1-22331582216e".
template <size_t N>
constexpr std::array<uint8_t, 16> UUIDFromString(const char (&str)[N])
{
// Note you have to include the null byte.
static_assert(N == 37, "Invalid GUID length.");
return std::array<uint8_t, 16>{
hexToByte<str[0], str[1]>(),
hexToByte<str[2], str[3]>(),
Perché str[0]
non è un'espressione costante.
Eventuali duplicati di [C++ 11 - static_assert nella funzione constexpr?] (http://stackoverflow.com/questions/8626055/c11-static-assert-within-constexpr-function) Controlla la seconda risposta che utilizza i modelli. – AndyG
@AndyG non funziona per questo caso poiché l'OP utilizza string letterali e non possono essere associati a template non paramter –
@AndyG Considererei questo in realtà un problema molto più specifico del caso generale che si collega a. –