Constexpr не вычисляется при вычислении с использованием внешней функции переменной const

#c #constexpr

Вопрос:

Я представляю два фрагмента кода, один из которых компилируется, а другой-нет.

Тот, который не компилируется:

 class Solution {
    public:
    const int MAX_NUM = 100;
    const int MAX_SIZE = 200;
    bool canPartition(vector<int>amp; 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>amp; 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 должен быть немедленно инициализирован.

Он должен иметь постоянное разрушение, т. е. он не относится к классовому типу

Не могли бы вы указать, в чем здесь проблема, и помочь мне понять проблему?

Комментарии:

1. неявное использование указателя «this» разрешено только при оценке вызова функции-члена «constexpr». Этим все сказано, в вашей первой версии MAX_NUM и MAX_SIZE являются членами класса. И будет косвенно использовать указатель «это». Во второй версии вы используете локальные переменные (константы), и это отлично подходит для оценки размера набора битов (указатель «this» не требуется).

2. Намеревались ли вы разрешить MAX_NUM и MAX_SIZE варьировать от объекта к объекту? Поскольку они есть const , они не могут быть изменены после построения, но (поскольку это не static так ) конструктору будет разрешено инициализировать эти поля другими значениями на основе объекта за объектом (отсюда необходимость доступа this к ним через функцию-член, но это лакомый кусочек больше для ответа, чем для этого запроса на уточнение).

3. Я понимаю. Спасибо @PKramer

4. Привет @JaMiT. Нет, я не собирался их менять. Я объявил их статичными, и это сработало! Теперь я понимаю ошибку. Спасибо всем за помощь.

Ответ №1:

Проблема в том, что, поскольку шаблоны оцениваются во время компиляции, их аргументы не могут быть чем-то таким, что компилятор не может «предсказать». В вашем первом коде переменные-члены MAX_NUM и MAX_SIZE являются const значениями, то есть они не могут быть изменены после создания экземпляра класса 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;
}
 

Как вы можете видеть const , вызываемой переменной-членом m_foo может быть любое значение, введенное пользователем.

Однако при определении const переменной в области действия функции это значение не может быть изменено и поэтому квалифицируется как аргумент шаблона, т. е. аналогично a constexpr .

Ответ №2:

Сообщения об ошибках довольно хорошо объясняют, что происходит. Аргумент шаблона для объявления bits должен быть постоянным выражением. Однако, если вы используете нестатические элементы, например MAX_NUM , внутри функции-члена, не являющейся constexpr, вы в конечном итоге вычисляете this указатель, что недопустимо. ссылка:

Базовым постоянным выражением является любое выражение, оценка которого не будет оценивать ни одно из следующих:

  1. this указатель, за исключением функции constexpr, которая вычисляется как часть выражения

Когда переменные типа MAX_NUM объявляются внутри функции-члена, они не являются членами класса, и поэтому их можно использовать в качестве постоянных выражений, поэтому первая версия компилируется.

Комментарии:

1. Итак, похоже, что решение состоит в том , чтобы отметить MAX_NUM и MAX_SIZE как static , чтобы они не зависели от this указателя.

2. @PeteBecker Да, это одно из решений. Хотя, если эти переменные больше нигде не используются, они также могут быть объявлены внутри функции-члена.