Короткий ответ заключается в том, что это не только static
полезно, но и всегда будет желанным.
Во-первых, обратите внимание, что static
и constexpr
полностью независимы друг от друга. static
определяет время жизни объекта во время выполнения; constexpr
указывает, что объект должен быть доступен во время компиляции. Компиляция и исполнение являются несвязанными и несмежными как во времени, так и в пространстве. Поэтому, как только программа скомпилирована, constexpr
она больше не актуальна.
Каждая объявленная переменная constexpr
неявно, const
но const
и static
почти ортогональна (за исключением взаимодействия с static const
целыми числами.)
C++
Объектная модель (§1.9) требует , чтобы все объекты, кроме битовых полей занимают по меньшей мере , один байты памяти и имеют адреса; кроме того, все такие объекты, наблюдаемые в программе в данный момент, должны иметь разные адреса (пункт 6). Это совсем не требует, чтобы компилятор создавал новый массив в стеке для каждого вызова функции с локальным нестатическим константным массивом, потому что компилятор мог бы укрыться в as-if
принципе, при условии, что он может доказать, что никакой другой такой объект не может быть наблюдаемый.
К сожалению, доказать это будет непросто, если только функция не является тривиальной (например, она не вызывает никакой другой функции, тело которой не видно внутри единицы преобразования), поскольку массивы, более или менее по определению, являются адресами. Таким образом, в большинстве случаев нестатический const(expr)
массив нужно будет заново создавать в стеке при каждом вызове, что лишает его возможности вычислять его во время компиляции.
С другой стороны, локальный static const
объект является общим для всех наблюдателей, и, кроме того, он может быть инициализирован, даже если функция, в которой он определен, никогда не вызывается. Таким образом, ничего из вышеперечисленного не применимо, и компилятор может не только генерировать только один его экземпляр; он может генерировать один экземпляр в хранилище только для чтения.
Так что вы обязательно должны использовать static constexpr
в своем примере.
Тем не менее, есть один случай, когда вы не хотите использовать static constexpr
. Если constexpr
объявленный объект не используется ODR или не объявлен static
, компилятор может вообще не включать его. Это очень полезно, поскольку позволяет использовать временные constexpr
массивы во время компиляции, не загрязняя скомпилированную программу ненужными байтами. В этом случае вы явно не захотите использовать static
, поскольку static
, вероятно, вынудите объект существовать во время выполнения.
const
отconst
объекта, только изconst X*
которых указывает наX
. Но дело не в этом; Дело в том, что автоматические объекты не могут иметь статические адреса. Как я уже говорил,constexpr
перестает быть значимым , как только компиляция закончится, так что нет ничего разбрасывать (и , вполне возможно , вообще ничего, так как объект не гарантируется даже существовать во время выполнения.)static
иconstexpr
но объяснить , что они ортогональны и независимы, делать разные вещи. Затем вы упоминаете причину, по которой НЕ объединять эти два параметра, так как это будет игнорировать использование ODR (что кажется полезным). Да, и я до сих пор не понимаю, почему static следует использовать с constexpr, так как static предназначен для работы во время выполнения. Вы никогда не объясняли, почему важно использовать static с constexpr.static constexpr
(это предотвращает повторное создание константного массива при каждом вызове функции), но я подправил некоторые слова, которые могут сделать его более понятным. Спасибо.constexpr
постоянная переменная используется только в контекстах времени компиляции и никогда не нужна во время выполнения, тоstatic
это не имеет смысла, поскольку к моменту, когда вы добираетесь до времени выполнения, значение эффективно «встроено». Тем не менее, еслиconstexpr
он используется в контекстах времени выполнения (другими словами,constexpr
он должен бытьconst
неявно преобразован и доступен с физическим адресом для кода времени выполнения), он захочетstatic
обеспечить соответствие ODR и т. Д. Это, по крайней мере, мое понимание.static constexpr int foo = 100;
. Нет никаких причин, по которым компилятор не мог бы заменить использованиеfoo
везде буквальным100
, если код не делал что-то подобное&foo
. Так чтоstatic
наfoo
нет полезность в этом случае , так какfoo
не существует во время выполнения. Опять все до компилятора.В дополнение к данному ответу, стоит отметить, что компилятору не требуется инициализировать
constexpr
переменную во время компиляции, зная, что разница между вамиconstexpr
и вstatic constexpr
том, чтоstatic constexpr
вы используете ее, гарантируют, что переменная инициализируется только один раз.Следующий код демонстрирует, как
constexpr
переменная инициализируется несколько раз (хотя с одним и тем же значением), в то времяstatic constexpr
как, безусловно, инициализируется только один раз.Кроме того, код сравнивает преимущество
constexpr
противconst
в сочетании сstatic
.Возможный вывод программы:
Как видите,
constexpr
инициализация выполняется несколько раз (адрес не совпадает), аstatic
ключевое слово гарантирует, что инициализация выполняется только один раз.источник
constexpr const short constexpr_short
для выдачи ошибки, если constexpr_short снова инициализируетсяconstexpr const
не имеет смысла, потому чтоconstexpr
уже естьconst
, добавлениеconst
один или несколько раз игнорируется компилятором. Вы пытаетесь поймать ошибку, но это не ошибка, так работает большинство компиляторов.