Какова цель маркировки функции set (setter) как constexpr?

Я не могу понять цель пометки функции-установщика как constexpr, что разрешено начиная с С++ 14. Мое недопонимание исходит из следующей ситуации: я объявляю класс с c-tor constexpr и собираюсь использовать его в контексте constexpr, создав экземпляр constexpr этого класса constexpr Point p1. Объект p1 теперь является постоянным, и его значение не может быть изменено, поэтому не может быть вызван установщик constexpr. С другой стороны, когда я создаю экземпляр моего class Point в Point p контекста non-constexpr, я могу вызвать установщик для этого объекта, но теперь установщик не будет выполняться во время компиляции, потому что объект не является constexpr!

В результате я не понимаю, как я могу повысить производительность своего кода, используя constexpr для сеттеров.

Этот код демонстрирует вызов установщика constexpr для объекта не-constexpr, что означает вычисление во время выполнения вместо времени компиляции:

class Point {
public:
    constexpr Point(int a, int b)
    : x(a), y(b) {}

    constexpr int getX() const noexcept { return x; }
    constexpr int getY() const noexcept { return y; }

    constexpr void setX(int newX) noexcept { x = newX; }
    constexpr void setY(int newY) noexcept { y = newY; }
private:
    int x;
    int y;
};


int main() {
    Point p{4, 2};
    constexpr Point p1{4, 2};

    p.setX(2);
}

Может ли кто-нибудь помочь мне понять, какова цель маркировки функции сеттера как constexpr?

Ответ 1

В основном это хорошо, когда вам приходится иметь дело с функцией constexpr.

struct Object {
  constexpr void set(int n);
  int m_n = 0;
};

constexpr Object function() {
   Object a;
   a.set(5);
   return a;
}

constexpr Object a = function();

Идея состоит в том, чтобы иметь возможность выполнять инициализацию во время компиляции в других функциях, которые будут выполняться во время компиляции. Это не сделано для применения к объекту constexpr.

Еще вещи, чтобы знать, что constexpr функции - члены не являются const функции Член с 14 :) С++.

Ответ 2

Необходимость возникает в новом правиле constexpr с С++ 14: внутри функции constexpr теперь можно использовать несколько операторов, в том числе для циклов и потока управления.

Вот пример:

constexpr int count5(int start) {
    int acc = 0;

    for (int i = start ; i<start+5 ; ++i) {
        acc += i;
    }

    return acc;
}

constexpr int value = count5(10); // value is 60!

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

Ответ 3

Функция с квалификатором constexpr будет оценивать возврат функции во время компиляции, что может значительно повысить производительность программы (без дополнительных вычислений, без скачков счетчиков команд и т.д.). Есть несколько требований, чтобы квалифицировать функцию таким образом, поэтому посмотрите это объяснение в IBM.