为什么声明为static constexpr的数组无法用整数变量作为下标访问?
问题原因
根本原因:C++17之前的静态constexpr成员ODR规则限制
- 硬编码下标访问正常的原因:当使用编译期常量作为下标访问时,编译器会直接在编译阶段把表达式替换为对应常量值,不需要读取
aIvoryKeys的内存地址,仅依赖类内的声明就能完成编译,不会触发链接阶段的符号查找。 - 变量下标访问报错的原因:当使用运行时变量作为下标时,编译器无法在编译期确定具体取值,需要对
aIvoryKeys进行ODR(单一定义规则)使用,也就是要获取数组的内存基地址,运行时动态计算偏移取值。而C++17之前的标准规定,类内声明的static constexpr成员仅属于声明,不属于定义,没有实际的内存实体,链接阶段找不到对应符号就会抛出undefined reference错误。 - 移除
static constexpr后正常的原因:去掉static后数组属于类实例的成员变量,实例化时会自动分配内存;如果仅去掉constexpr保留static,依然会遇到相同的未定义引用错误,本质和constexpr无关,是静态成员的定义规则问题。
解决方案
- 方案1(推荐):升级到C17及以上标准编译。C17开始类内声明的
static constexpr成员默认是隐式内联的,不需要额外定义,自动生成内存实体,原有代码不需要任何修改即可正常编译运行。 - 方案2(兼容C++11/14):在类定义的外部补充一行静态成员的定义即可,不需要重复写初始化值:
// 类定义外补充这一行 constexpr unsigned short int KeyboardKey::aIvoryKeys[];
补充说明:你的理解完全正确,constexpr数组本身完全支持运行时访问,只是不可修改,这个问题和访问权限、constexpr的运行时可用性没有关系,只是C++旧版本的静态成员定义规则导致的链接问题。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

