C++类const成员作为bitset模板参数编译失败原因是什么?
C++代码编译失败原因解释
两段代码对比
编译失败代码
class Solution { public: const int MAX_NUM = 100; const int MAX_SIZE = 200; bool canPartition(vector<int>& nums) { bitset<(MAX_NUM*MAX_SIZE)/2 + 1> bits(1); int sum = 0; for(int num: nums) { sum += num; bits |= bits << num; } return !(sum % 2) and bits[sum/2]; } };
报错信息:
error: non-type template argument is not a constant expression implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function
编译成功代码
class Solution { public: bool canPartition(vector<int>& nums) { const int MAX_NUM = 100; const int MAX_SIZE = 200; bitset<(MAX_NUM*MAX_SIZE)/2 + 1> bits(1); int sum = 0; for(int num: nums) { sum += num; bits |= bits << num; } return !(sum % 2) and bits[sum/2]; } };
根本原因
类内定义的非静态const成员变量不属于编译期常量表达式,无法满足std::bitset对非类型模板参数必须编译期可确定值的要求。
相关原理说明
std::bitset的长度参数属于非类型模板参数,C++标准明确要求非类型模板参数必须是编译期就能确定值的常量表达式,运行时才能确定的值不能用作该参数。- 局部
const变量和类非静态const成员的属性有本质区别:- 函数内部定义、且直接用字面值初始化的局部
const变量,值在编译阶段就能完全确定,属于合法的常量表达式,所以第二段代码可以正常编译。 - 类内的非静态
const成员哪怕给定了默认初始值,本质上仍然是归属于类实例的成员,后续完全可以通过构造函数初始化列表覆盖这个默认值,它的值要到类实例创建的运行阶段才能最终确定。编译器处理时会将MAX_NUM解析为this->MAX_NUM,而this指针是运行时对象的地址,编译阶段无法获取对应的值,自然不满足常量表达式的要求,因此抛出对应的报错。
- 函数内部定义、且直接用字面值初始化的局部
- 如果要在类作用域下定义可用于模板参数的常量,可以将成员声明为
static constexpr类型:static constexpr int MAX_NUM = 100;,此时变量属于类全局的编译期常量,不绑定到具体类实例,就可以正常用作bitset的模板参数。
内容的提问来源于stack exchange,提问作者Laschet Jain
相关产品推荐
相关产品推荐

