Где в стандарте C ++ 11 указано, когда функция constexpr может быть оценена во время перевода?

Просто потому, что функция (или конструктор) …

  • объявляется constexpr и
  • определение функции соответствует требованиям constexpr

…не означает, что компилятор будет оценивать функцию constexpr во время перевода. Я просматривал C ++ 11 FDIS (N3242, доступен на http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/) попытаться определить две вещи:

  • Когда компилятор обязан оценивать функцию constexpr во время перевода?
  • Когда компилятору разрешается оценивать функцию constexpr во время перевода?

Раздел 5.19 В параграфе 1 говорится, что константные выражения могут быть оценены во время перевода. Насколько я могу понять, в оставшейся части раздела 5.19 изложены правила того, что действительно в определении функции constexpr.

Я понимаю, что могу принудительно оценить constexpr во время перевода, объявив результат функции constexpr как constexpr. Как это:

// Declaration
constexpr double eulers_num() { return 2.718281828459045235360287471; }

// Forced evaluation during translation
constexpr double twoEulers = eulers_num() * 2.0;
static_assert(twoEulers > 5.0, "Yipes!");

До сих пор я не смог найти параграфы в FDIS, которые:

  • сила twoEulers оценивать во время перевода или
  • Укажите другие ситуации, когда компилятор может или должен оценивать функцию constexpr во время перевода.

Что меня особенно интересует, так это то, что оценка constexpr во время перевода инициируется:

  1. Когда все параметры, переданные функции constexpr, являются литералами, или
  2. подразумеваемый объектный аргумент во время разрешения перегрузки (раздел 13.3.1, параграф 3) либо constexpr, либо требуется литерал (например, для измерений массива), либо
  3. Что-то еще целиком.

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

18

Решение

«Разрешено» оценивать constexpr вызывать во время компиляции всякий раз, когда это возможно. Помните, что спецификация работает по правилу «как будто». Так что, если вы не можете определить разницу, компилятор может делать все, что захочет.

Компилятор требуется оценить constexpr вызовы во время компиляции, когда это на самом деле потребности ответ во время компиляции. Например:

constexpr int foo() {return 5;}

std::array<float, foo()> arr;

Компилятор должен знать размер массива во время компиляции. Следовательно, он должен оценивать константное выражение во время компиляции. Если constexpr функция не может быть выполнена во время компиляции, вы получаете ошибку во время компиляции.

6

Другие решения

Никол Болас прав на 100%, но есть еще один интересный аспект: оценивается ли выражение во время перевода и оценивается ли оно во время выполнения — это совершенно независимые вопросы. Поскольку константное выражение не может иметь побочных эффектов, оно может оцениваться произвольное количество раз, и ничто не мешает его оценить как во время перевода, так и во время выполнения.

Предположим, что константное выражение было большим массивом (не std::arrayпросто массив), что вполне допустимо, и программа не указывает, что у него есть статическое хранилище. Предположим также, что только элемент 7 массива используется в контексте, в котором необходимо вычисление во время компиляции. Вполне разумно, чтобы компилятор вычислял весь массив, использовал элемент 7, отбрасывал его и вставлял код для его вычисления во время выполнения в той области, в которой он используется, вместо того, чтобы разбивать двоичный файл на весь вычисляемый массив. Я считаю, что это не теоретическая проблема; Я наблюдал это с разными компиляторами в разных контекстах. constexpr делает не подразумевать static,

Конечно, если компилятор может определить, что массив не используется во время выполнения, он может даже не вставить код для его вычисления, но это еще одна проблема.

Если вы используете такой объект во время выполнения и хотите указать компилятору, что его стоит хранить в течение всей программы, вы должны объявить его как static,

4

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

Раздел 3.6.2 Инициализация нелокальных переменных, в параграфе 2 говорится, что если объект со статическим или локальным временем хранения потока инициализируется constexpr конструктор, то конструктор оценивается во время перевода:

Постоянная инициализация выполняется:

  • если объект со статическим или потоковым сроком хранения инициализируется вызовом конструктора, если конструктор является constexpr конструктор, если все аргументы конструктора являются константными выражениями (включая преобразования), и если после подстановки вызова функции (7.1.5), каждый вызов конструктора и полное выражение в MEM-Инициализаторы является постоянным выражением;

Раздел 7.1.5 Спецификатор constexpr, в пункте 9 говорится, включает ли объявление объекта constexpr Спецификатор, этот объект оценивается во время перевода (т.е. является литералом):

constexpr спецификатор, используемый в объявлении объекта, объявляет объект как const. Такой объект должен иметь буквальный тип и должен быть инициализирован. Если он инициализируется вызовом конструктора, этот вызов должен быть константным выражением (5.19). В противном случае каждое полное выражение, которое появляется в его инициализаторе, должно быть константным выражением. Каждое неявное преобразование, используемое при преобразовании выражений инициализатора, и каждый вызов конструктора, используемый для инициализации, должен быть одним из тех, которые разрешены в константном выражении (5.19).

Я слышал, что люди утверждают, что этот абзац оставляет пространство для реализации, чтобы отложить инициализацию до времени выполнения, если эффект не может быть обнаружен во время перевода из-за, скажем, static_assert, Вероятно, это не совсем точное представление, потому что при некоторых обстоятельствах можно наблюдать, инициализировано ли значение во время перевода. Эта точка зрения подкрепляется Раздел 5.19. Постоянные выражения пункт 4:

[ Замечания: Хотя в некоторых контекстах константные выражения должны оцениваться во время трансляции программы, другие могут оцениваться во время выполнения программы. Поскольку данный международный стандарт не накладывает никаких ограничений на точность операций с плавающей запятой, не определено, дает ли оценка выражения с плавающей запятой во время перевода тот же результат, что и оценка того же выражения (или тех же операций с теми же значениями) ) во время выполнения программы … — конечная нота ]

Раздел 9.4.2 Статические данные членов, в параграфе 3 говорится, что если постоянный статический член данных литерального типа инициализируется функцией или конструктором constexpr, то эта функция или конструктор должны быть оценены во время перевода:

Если статический член данных имеет константный литеральный тип, его объявление в определении класса может указывать скобка-orequal-инициализатор в котором каждый инициализатор-раздел это Назначение выражение это постоянное выражение. Статический член данных литерального типа может быть объявлен в определении класса с помощью constexpr спецификатор; если это так, в его декларации указывается скобки или равно-инициализатор в котором каждый инициализатор-раздел то есть выражение присваивания является константным выражением. [ Замечания: В обоих этих случаях член может появляться в постоянных выражениях. — конечная нота ]

Интересно, что я не нашел в FDIS ничего, что требовало бы constexpr Выражение для оценки, если его результат используется в качестве измерения массива. Я вполне уверен, что стандартный комитет ожидает, что это будет так. Но я также мог пропустить это в моих поисках.

Вне этих обстоятельств стандарт C ++ 11 позволяет вычисления в функциях и конструкторах constexpr, выполняемые во время перевода. Но это не требует этого. Вычисления могут произойти во время выполнения. Какие вычисления выполняет компилятор во время перевода, в некоторой степени является вопросом качества реализации.

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

Итак, чтобы добраться до реальной точки зрения, кажется, что constexpr Оценка во время перевода инициируется:

  • Подразумеваемый аргумент объекта во время разрешения перегрузки (Раздел 13.3.1, Параграф 3) либо является constexpr, либо требует литерала.

Я надеюсь, что это полезно для кого-то, кроме меня. Спасибо всем, кто внес свой вклад.

4

Я не думаю, что это где-то принудительно. Я тоже посмотрел, это сложно, потому что в списке нет ни одной статьи на constexpr; кажется, все они добавляют / удаляют из предыдущей коллекции документов.

Я думаю, что общая идея состоит в том, что когда входные данные для функции constexpr сами являются constexpr, все это будет сделано во время компиляции; кроме того, не функциональные операторы constexpr, которые в любом случае являются литеральными, будут выполняться во время компиляции, если вы используете наполовину интеллектуальный компилятор.

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

из википедии

который, кажется, получить информацию от этот PDF:

Функции constexpr: функция constexpr — это функция, которая
достаточно просто », так что он обеспечивает постоянное выражение, когда
вызывается с аргументами, которые являются постоянными значениями (см. §2.1).

1
А ты уже прошел курс программирования? Супер скидка!
Прокачать скилл $$$
×