C++ 带有constexpr的编译时数组 //codenz.cpp constexpr uint32_t散列[]= { //ntdll crc32::生成(“memcpy”), //内核32 crc32::生成(“MessageBoxA”) }; //hash.hpp #包括 #包括 名称空间crc32 { //生成CRC查找表 模板 结构f:f>1),k-1>{}; 模板结构f{enum{value=c};}; #定义A(x)B(x)B(x+128) #定义B(x)C(x)C(x+64) #定义C(x)D(x)D(x+32) #定义D(x)E(x)E(x+16) #定义E(x)F(x)F(x+8) #定义F(x)G(x)G(x+4) #定义G(x)H(x)H(x+2) #定义H(x)I(x)I(x+1) #定义I(x)f::value, constexpr无符号crc_表[]={A(0)}; //Constexpr实现和帮助程序 constexpr uint32\u t crc32\u impl(constep uint8\u t*p,尺寸长度,uint32\u t crc){ 回蓝? crc32_impl(p+1,len-1,(crc>>8)^crc_表[(crc&0xFF)^*p]) :crc; } constexpr uint32\u t crc32(const uint8\u t*数据、大小和长度){ 返回~crc32_impl(数据,长度,~0); } constexpr size\u t strlen\u c(const char*str){ return*str?1+strlen_c(str+1):0; } constexpr uint32_t生成(const char*str){ 返回crc32((uint8_t*)str,strlen_c(str)); } }
正如您所看到的,函数本身和数组是C++ 带有constexpr的编译时数组 //codenz.cpp constexpr uint32_t散列[]= { //ntdll crc32::生成(“memcpy”), //内核32 crc32::生成(“MessageBoxA”) }; //hash.hpp #包括 #包括 名称空间crc32 { //生成CRC查找表 模板 结构f:f>1),k-1>{}; 模板结构f{enum{value=c};}; #定义A(x)B(x)B(x+128) #定义B(x)C(x)C(x+64) #定义C(x)D(x)D(x+32) #定义D(x)E(x)E(x+16) #定义E(x)F(x)F(x+8) #定义F(x)G(x)G(x+4) #定义G(x)H(x)H(x+2) #定义H(x)I(x)I(x+1) #定义I(x)f::value, constexpr无符号crc_表[]={A(0)}; //Constexpr实现和帮助程序 constexpr uint32\u t crc32\u impl(constep uint8\u t*p,尺寸长度,uint32\u t crc){ 回蓝? crc32_impl(p+1,len-1,(crc>>8)^crc_表[(crc&0xFF)^*p]) :crc; } constexpr uint32\u t crc32(const uint8\u t*数据、大小和长度){ 返回~crc32_impl(数据,长度,~0); } constexpr size\u t strlen\u c(const char*str){ return*str?1+strlen_c(str+1):0; } constexpr uint32_t生成(const char*str){ 返回crc32((uint8_t*)str,strlen_c(str)); } },c++,arrays,c++11,metaprogramming,constexpr,C++,Arrays,C++11,Metaprogramming,Constexpr,正如您所看到的,函数本身和数组是constexpr,因此应该在编译时进行计算。MSVC编译器抛出一个错误“表达式的计算结果不是常量”。为什么呢 您应该删除冗余强制转换: // codenz.cpp constexpr uint32_t Hashes[] = { // ntdll crc32::generate("memcpy"), // kernel32 crc32::generate("MessageBo
constexpr
,因此应该在编译时进行计算。MSVC编译器抛出一个错误“表达式的计算结果不是常量”。为什么呢 您应该删除冗余强制转换:
// 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 uint32\u t crc32\u impl(const char*p,size\u t len,uint32\u t crc){
回蓝?
crc32_impl(p+1,len-1,(crc>>8)^crc_表[(crc&0xFF)^static_cast(*p)])
:crc;
}
constexpr uint32\u t crc32(const char*数据,大小\u t长度)
{
返回~crc32_impl(数据,长度,~0);
}
//我们可以一次性获得字符串文字数组大小
模板constexpr uint32\u t
生成(常量字符(&str)[V\u数组\u项目\u计数])
{
返回crc32(str,V_数组_项目_计数-1);
}
或者,如果您希望保持crc32接口接受
uint8\t
或字节
,则可能需要在编译时构建相应的副本数组。您应该删除冗余强制转换:
// 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 uint32\u t crc32\u impl(const char*p,size\u t len,uint32\u t crc){
回蓝?
crc32_impl(p+1,len-1,(crc>>8)^crc_表[(crc&0xFF)^static_cast(*p)])
:crc;
}
constexpr uint32\u t crc32(const char*数据,大小\u t长度)
{
返回~crc32_impl(数据,长度,~0);
}
//我们可以一次性获得字符串文字数组大小
模板constexpr uint32\u t
生成(常量字符(&str)[V\u数组\u项目\u计数])
{
返回crc32(str,V_数组_项目_计数-1);
}
或者,如果您想让crc32接口接受
uint8\t
或byte
,则可能需要在编译时构建相应的副本数组。MSVC的constexpr支持随着时间的推移而不断改进。如果您使用的版本不能处理这种情况,我不会感到惊讶,但是如果没有一个或编译器版本,很难说。@chris我用一个完整的例子编辑了这篇文章。GCC也抱怨,尽管错误更好。MSVC的constexpr支持随着时间的推移一直在改进。如果您使用的版本不能处理这种情况,我不会感到惊讶,但是如果没有一个或编译器版本,很难说。@chris我用一个完整的例子编辑了这篇文章。GCC也会抱怨,尽管错误更好。感谢您的建议,幸运的是这并不能解决核心问题。@Swagov3rflow您所说的“不能解决核心问题”是什么意思。问题是,您有那些不能在常量表达式中使用的额外强制转换。当在数组外部使用它时,代码在更改之前运行良好(它在编译时生成了值,我对此进行了检查)。“核心问题”是它在数组中不工作。@Swagov3rflow“它在数组中不工作”是什么意思?“联机编译器链接”演示了仍然生成哈希值
数组的完整工作示例。当使用您的更改(msvc编译器)在本地运行程序时,数组中的值为0。感谢您的建议,幸运的是,这并不能解决核心问题。@Swagov3rflow您的意思是什么“无法解决核心问题/问题”。问题是您有无法在常量表达式中使用的额外强制转换。在更改之前,代码在数组外部使用时运行良好(它在编译时生成了值,我对此进行了检查)。“核心问题”“它在数组中不工作。@Swagov3rflow“它在数组中不工作”是什么意思?联机编译器链接演示了仍然构建哈希值
数组的完整工作示例。在本地运行带有更改的程序(msvc编译器)时,数组中的值为0。