在函数外使用 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:

  1. the this pointer, except in a constexpr function that is being evaluated as part of the expression

MAX_NUM这样的变量声明在成员函数内部时,它们不是class的成员,所以它们可以用作常量表达式,这就是为什么第一个版本编译。

问题在于,由于模板是在编译时计算的,因此它们的参数不能是编译器无法“预测”的任何内容。在您的第一个代码中,成员变量 MAX_NUMMAX_SIZEconst 值,这意味着它们在创建 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_fooconst成员变量可以是用户输入的任何值。

但是,在函数范围内定义 const 变量时,该值无法更改,因此被限定为模板参数,即它是类似于 constexpr.