简体   繁体   English

使用constexpr的编译时数组

[英]Compiletime array with 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));
    }
}

As you can see the function itself and the array is constexpr and thus should be evaluated at compile time. 如您所见,函数本身以及数组为constexpr ,因此应在编译时进行评估。 The MSVC compiler spits out an error that "expression did not evaluate to a constant". MSVC编译器吐出一个错误,“表达式未求值为常数”。 Why is that? 这是为什么?

You should remove redundant casts: 您应该删除多余的演员表:

// 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 在线编译器

Alternatively if you want to keep crc32 interface to accept uint8_t or byte then you may need to build a corresponding copy array at compile time. 或者,如果您想保留crc32接口以接受uint8_tbyte则可能需要在编译时构建相应的副本数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM