带有 constexpr 的编译时数组

Compiletime array with constexpr

本文关键字:数组 编译 constexpr 带有      更新时间:2023-10-16
// codenz.cpp
constexpr uint32_t Hashes[] =
{
// ntdll
crc32::generate("memcpy"),
// kernel32
crc32::generate("MessageBoxA")
};
// hash.hpp
#include <cstring>
#include <cstdint>
namespace crc32
{
// Generate CRC lookup table
template <unsigned c, int k = 8>
struct f : f<((c & 1) ? 0xedb88320 : 0) ^ (c >> 1), k - 1> {};
template <unsigned c> struct f<c, 0> { enum { value = c }; };
#define A(x) B(x) B(x + 128)
#define B(x) C(x) C(x +  64)
#define C(x) D(x) D(x +  32)
#define D(x) E(x) E(x +  16)
#define E(x) F(x) F(x +   8)
#define F(x) G(x) G(x +   4)
#define G(x) H(x) H(x +   2)
#define H(x) I(x) I(x +   1)
#define I(x) f<x>::value ,
constexpr unsigned crc_table[] = { A(0) };
// Constexpr implementation and helpers
constexpr uint32_t crc32_impl(const uint8_t* p, size_t len, uint32_t crc) {
return len ?
crc32_impl(p + 1, len - 1, (crc >> 8) ^ crc_table[(crc & 0xFF) ^ *p])
: crc;
}
constexpr uint32_t crc32(const uint8_t* data, size_t length) {
return ~crc32_impl(data, length, ~0);
}
constexpr size_t strlen_c(const char* str) {
return *str ? 1 + strlen_c(str + 1) : 0;
}
constexpr uint32_t generate(const char* str) {
return crc32((uint8_t*)str, strlen_c(str));
}
}

如您所见,函数本身和数组是constexpr的,因此应在编译时进行计算。MSVC 编译器吐出"表达式未计算为常量"的错误。为什么?

您应该删除多余的强制转换:

// now we only need one static cast
constexpr uint32_t crc32_impl(const char * p, size_t len, uint32_t crc) {
return len ?
crc32_impl(p + 1, len - 1, (crc >> 8) ^ crc_table[(crc & 0xFF) ^ static_cast< unsigned char >(*p)])
: crc;
}
constexpr uint32_t crc32(const char * data, size_t length)
{
return ~crc32_impl(data, length, ~0);
}
// we can obtain string literal array size at one go
template<size_t V_array_items_count> constexpr uint32_t
generate(const char ( & str )[V_array_items_count])
{
return crc32(str, V_array_items_count - 1);
}

在线编译器

或者,如果你想让crc32接口接受uint8_tbyte那么你可能需要在编译时构建一个相应的复制数组。