Подтвердить что ты не робот

Передача аргументов функции constexpr

Я новичок в программировании, и я начал узнавать об этом, используя книгу Принципы программирования и практику с использованием С++. Сегодня я здесь, потому что у меня есть некоторые проблемы в понимании функций constexpr. В главе 8 автор вводит их в некоторые строки и краткий пример, используя эти слова:

Функция представляет собой вычисление, и иногда мы хотим сделать расчет во время компиляции. Причина, по которой требуется вычисление, вычисляемое компилятором, обычно заключается в том, чтобы избежать того же вычисления, выполненного миллионы раз во время выполнения.

Мы сообщаем, что будем иметь функцию, оцененную во время компиляции, объявив функцию как функцию constexpr. Функция constepxr может быть оценена во время компиляции, только если ей заданы постоянные выражения в качестве аргументов.

constexpr double xscale = 10; // scaling factors 
constexpr double yscale = 0.8; 
constexpr Point scale(Point p) { return { xscale*p.x, yscale*p.y }; };

Предположим, что точка - это простая структура с элементами x и y, представляющими двумерные координаты. Теперь, когда мы даем аргумент scale() a Point, он возвращает точку с координатами, масштабированными в соответствии с факторами xscale и yscale. Например:

void user(Point p1) {

Point p2{10,10}; 

Point p3 = scale(p1); 
Point p4 = scale(p2) // p4 == {100,8}

constexpr Point p5 = scale(p1); // error : scale(p1) is not a constant expression
constexpr Point p6 = scale(p2); // p6 == {100,8};

Мой вопрос: Почему мы можем использовать p2 в качестве аргумента для scale()? Является ли p2 постоянным выражением? И если да, то почему?

Можно ли считать элементы данных x и y постоянными выражениями?

Моя книга не дает слишком много информации, поэтому у меня возникают некоторые проблемы с этой концепцией.

4b9b3361

Ответ 1

В принципе, функции constexpr могут выполняться во время компиляции или времени выполнения в зависимости от контекста. Гарантируется выполнение во время компиляции только в том случае, если все его параметры constexpr, и его результат используется в контексте, требующем constexpr (например, присвоение значения constexpr, параметр шаблона или, скажем, размер массива c-style). В противном случае он оценивается во время выполнения как любая другая функция. Таким образом, строки p3 и p4 выполняются во время выполнения, тогда как p5 дает ошибку, потому что scale(p1) не constexpr, и фактически p6 также должен давать вам ошибку, если вы не добавите constexpr к определению p2. Пример здесь.

Ответ 2

Почему мы можем использовать p2 в качестве аргумента для scale()?

Потому что scale() записывается, чтобы принять что-либо, что является Point или неявно конвертируется в Point. В этом случае p2 имеет тип Point. Следовательно, его можно использовать в качестве аргумента для scale().

Рассматривается ли p2 как постоянное выражение? И если да, то почему?

p2 фактически объявляется как локальная переменная. Когда он используется как:

constexpr Point p6 = scale(p2);

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

В следующем случае:

constexpr Point p5 = scale(p1);

p1 передается как аргумент user() и может иметь любое значение, которое может быть известно только во время выполнения, следовательно, ошибка.

Ответ 3

Мне кажется, что он получил в книге. Похоже, что это должно быть

constexpr Point p2{10,10};

только в этом случае любой современный компилятор не даст ошибка по вызову

constexpr Point p6 = scale(p2); // p6 == {100,8};

потому что вы пытаетесь инициализировать переменную constexpr с результатом функции, которая будет оцениваться во время выполнения (если p2 не объявлено constexpr).