C++数组的数组定义方法及VS2015编译错误修复方案
解决VS2015中constexpr数组初始化的编译器内部错误及类型不匹配问题
这个问题我之前碰到过,VS2015对constexpr C风格数组的聚合初始化确实存在兼容性bug。咱们先拆解下问题根源:你定义的myType是uint8_t[16]这种C风格数组类型,当尝试把x0、x1、x2这些constexpr数组放进AllX数组时,IntelliSense会误把数组退化为指针(const uint8_t*),和AllX期望的const uint8_t[][16]类型不匹配;而编译器报内部错误,则是VS2015对这种constexpr数组聚合初始化的支持不完善导致的。
下面给你两种可行的解决办法:
方法一:改用std::array替代C风格数组(推荐)
std::array是C++11引入的容器,本质是封装了C风格数组的类类型,VS2015对它的constexpr支持稳定得多。修改后的代码如下:
#include <array> #include <cstdint> using myType = std::array<uint8_t, 16>; constexpr myType x0 = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6}; constexpr myType x1 = {11,12,13,14,15,16,17,18,19,10,11,12,13,14,15,16}; constexpr myType x2 = {21,22,23,24,25,26,27,28,29,20,21,22,23,24,25,26}; constexpr std::array<myType, 3> AllX = {x0, x1, x2};
这种写法完全符合C++标准,既能避开VS2015的编译器bug,IntelliSense也不会再报错,而且代码可读性和维护性都更好。
方法二:手动展开C风格数组的初始化(兼容原有类型)
如果因为项目限制必须使用C风格数组,可以直接把每个数组的元素手动展开到AllX中,绕开数组到数组的初始化逻辑:
#include <cstdint> typedef uint8_t myType[16]; constexpr myType x0 = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6}; constexpr myType x1 = {11,12,13,14,15,16,17,18,19,10,11,12,13,14,15,16}; constexpr myType x2 = {21,22,23,24,25,26,27,28,29,20,21,22,23,24,25,26}; // 手动展开每个数组的元素进行初始化 constexpr uint8_t AllX[3][16] = { {x0[0], x0[1], x0[2], x0[3], x0[4], x0[5], x0[6], x0[7], x0[8], x0[9], x0[10], x0[11], x0[12], x0[13], x0[14], x0[15]}, {x1[0], x1[1], x1[2], x1[3], x1[4], x1[5], x1[6], x1[7], x1[8], x1[9], x1[10], x1[11], x1[12], x1[13], x1[14], x1[15]}, {x2[0], x2[1], x2[2], x2[3], x2[4], x2[5], x2[6], x2[7], x2[8], x2[9], x2[10], x2[11], x2[12], x2[13], x2[14], x2[15]} };
这种方法虽然繁琐,但能在VS2015中正常编译,保持原有C风格数组的类型不变。
另外提一句:如果你的项目允许升级编译器,VS2017及以后的版本已经修复了这个constexpr数组的编译器内部错误,直接使用你原来的代码就能正常编译通过。
内容的提问来源于stack exchange,提问作者mans




