使用constexpr进行编译时数组

时间:2017-12-03 20:19:51

标签: 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编译器吐出“表达式未评估为常量”的错误。这是为什么?

1 个答案:

答案 0 :(得分:2)

你应该删除多余的演员阵容:

// 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接口接受uint8_tbyte,那么您可能需要在编译时构建相应的副本数组。