c++ - 带有 constexpr 的编译时数组

标签 c++ arrays c++11 metaprogramming constexpr

    // 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);
}

online compiler

或者,如果您想保留 crc32 接口(interface)以接受 uint8_tbyte,那么您可能需要在编译时构建相应的拷贝数组。

关于c++ - 带有 constexpr 的编译时数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47622877/

相关文章:

c++ - 构造一个 void 类型?

c++ - move 构造函数和静态数组

c++ - 为什么没有分段元组构造?

c++ - 在什么情况下 C++ 会在编译时进行数组边界检查?

c++ - 如何连接一个 const char 数组和一个 char 数组指针?

Java数组打印出奇怪的数字和文本

c++ - 在B类中访问A类的函数f,而f需要访问B的成员变量

c++ - 删除 C 上的非通用模板参数

c++ - 为什么可以只给一个接受引用的函数一个对象(而不是一个引用)?是否自动生成引用?

c++ - 将unique_ptr vector 分配给 vector C++