在函数外使用 const 变量计算时,Constexpr 不会被评估
Constexpr doesn't get evaluated when computed using const variable outside function
我展示了两个代码片段,一个可以编译,另一个不能。
编译不通过的:
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];
}
};
我阅读了 constexpr
文档并发现了两个可能存在问题的地方:
constexpr must immediately initialized.
It must have constant destruction, i.e. it is not of class type
你能指出这里的问题是什么并帮助我理解问题吗?
错误消息很好地解释了发生了什么。 bits
声明的模板参数需要是常量表达式。但是,如果您在非 constexpr 成员函数中使用像 MAX_NUM
这样的非静态成员,您最终会评估 this
指针,这是不允许的。 ref:
A core constant expression is any expression whose evaluation would not evaluate any one of the following:
- the
this
pointer, except in a constexpr function that is being evaluated as part of the expression
当MAX_NUM
这样的变量声明在成员函数内部时,它们不是class的成员,所以它们可以用作常量表达式,这就是为什么第一个版本编译。
问题在于,由于模板是在编译时计算的,因此它们的参数不能是编译器无法“预测”的任何内容。在您的第一个代码中,成员变量 MAX_NUM
和 MAX_SIZE
是 const
值,这意味着它们在创建 class Solution
实例后无法更改,并且它们被初始化。但是对于Solution
的每个实例,它们仍然可以在构造函数中使用不同的、不可预测的值进行初始化。您设置的默认值它们等于(分别为 100 和 200)仅在实例创建期间未初始化时才使用。看看下面的代码:
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class A
{
private:
const int m_foo = 1;
public:
A() {}
A(int num) : m_foo(num) {}
int foo() { return m_foo; }
};
int main()
{
A a1; //a1.m_foo initialized with default value
cout << "Enter desired m_foo for a2: ";
int foo;
cin >> foo;
A a2(foo); //a2.m_foo initialized with user input
cout << "m_foo for a1: " << a1.foo() << endl
<< "m_foo for a2: " << a2.foo();
return 0;
}
如你所见,名为m_foo
的const
成员变量可以是用户输入的任何值。
但是,在函数范围内定义 const
变量时,该值无法更改,因此被限定为模板参数,即它是类似于 constexpr
.
我展示了两个代码片段,一个可以编译,另一个不能。
编译不通过的:
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];
}
};
我阅读了 constexpr
文档并发现了两个可能存在问题的地方:
constexpr must immediately initialized.
It must have constant destruction, i.e. it is not of class type
你能指出这里的问题是什么并帮助我理解问题吗?
错误消息很好地解释了发生了什么。 bits
声明的模板参数需要是常量表达式。但是,如果您在非 constexpr 成员函数中使用像 MAX_NUM
这样的非静态成员,您最终会评估 this
指针,这是不允许的。 ref:
A core constant expression is any expression whose evaluation would not evaluate any one of the following:
- the
this
pointer, except in a constexpr function that is being evaluated as part of the expression
当MAX_NUM
这样的变量声明在成员函数内部时,它们不是class的成员,所以它们可以用作常量表达式,这就是为什么第一个版本编译。
问题在于,由于模板是在编译时计算的,因此它们的参数不能是编译器无法“预测”的任何内容。在您的第一个代码中,成员变量 MAX_NUM
和 MAX_SIZE
是 const
值,这意味着它们在创建 class Solution
实例后无法更改,并且它们被初始化。但是对于Solution
的每个实例,它们仍然可以在构造函数中使用不同的、不可预测的值进行初始化。您设置的默认值它们等于(分别为 100 和 200)仅在实例创建期间未初始化时才使用。看看下面的代码:
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
class A
{
private:
const int m_foo = 1;
public:
A() {}
A(int num) : m_foo(num) {}
int foo() { return m_foo; }
};
int main()
{
A a1; //a1.m_foo initialized with default value
cout << "Enter desired m_foo for a2: ";
int foo;
cin >> foo;
A a2(foo); //a2.m_foo initialized with user input
cout << "m_foo for a1: " << a1.foo() << endl
<< "m_foo for a2: " << a2.foo();
return 0;
}
如你所见,名为m_foo
的const
成员变量可以是用户输入的任何值。
但是,在函数范围内定义 const
变量时,该值无法更改,因此被限定为模板参数,即它是类似于 constexpr
.