Почему постоянный указатель не может быть постоянным выражением?

StackOverflow https://stackoverflow.com/questions/7392057

Вопрос

Компилируется следующая программа:

общий

А вот этого нет, что для меня сюрприз:

общий

Альтернативный пример:

общий

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

Вопросы:

  1. Верно ли мое заключение?
  2. Если да, то почему указатель не может быть постоянным выражением?Если нет, то почему вышеуказанные программы не компилируются?
  3. Меняет ли что-нибудь C ++ 0x (C ++ 11, если хотите)?

Спасибо за любые идеи!

Это было полезно?

Решение

Это немного сложнее. В C ++ 03 и C ++ 11 &var является константным выражением, если var является локальной статической / статической переменной класса или переменной области пространства имен. Это называется выражением константы адреса. Инициализация переменной указателя статической области или области пространства имен с помощью этого константного выражения гарантированно будет выполнена до запуска любого кода (фаза статической инициализации), поскольку это постоянное выражение.

Однако только начиная с C ++ 11, переменная-указатель constexpr , в которой хранится код &var адреса, также может использоваться как выражение константы адреса, и только начиная с C ++ 11 вы можете разыменовать константу адреса выражение (на самом деле, вы можете разыменовать еще больше - даже адреса элементов локального массива, но давайте оставим его ontopic), и если оно относится к постоянной интегральной переменной, инициализированной до разыменования, или переменной constexpr, вы снова получите постоянное выражение (в зависимости от тип и категория значения, вид постоянного выражения может быть разным). Таким образом, для C ++ 11 допустимо следующее:

общий <цитата>

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

Это известное ограничение в формулировке Стандарта - в настоящее время в нем разрешены только другие параметры шаблона в качестве аргументов или & object для параметра шаблона типа указателя. Хотя компилятор должен уметь гораздо больше.

Другие советы

Это все еще запрещено в C ++ 0x. temp.arg.nontype требует:

<цитата>

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

  • для не типового параметра-шаблона целочисленного или перечислимого типа, преобразованное постоянное выражение (5.19) типа параметра-шаблона; или
  • имя не типового параметра шаблона; или
  • постоянное выражение (5.19), которое обозначает адрес объекта со статической продолжительностью хранения и внешняя или внутренняя связь или функция с внешней или внутренней связью, включая шаблоны функций и идентификаторы шаблонов функций, но исключая нестатические члены класса, выраженные (без учета круглых скобок) как & id-expression , за исключением того, что & может быть опущено, если имя относится к функции или массиву и должно опускаться, если соответствующий параметр-шаблон является ссылкой; или
  • постоянное выражение, вычисляющее значение нулевого указателя (4.10); или
  • константное выражение, которое возвращает значение указателя на нулевой член (4.11); или
  • указатель на член, выраженный, как описано в п. 5.3.1.

исходный ответ:

  1. В C ++ 03 только интегральные выражения могут быть постоянными выражениями.
  2. Потому что так сказано в стандарте (естественно).
  3. В C ++ 0x n3290 включает примеры с использованием кода constexpr для указателя. Итак, то, что вы пытаетесь сделать, теперь должно быть возможным, хотя теперь вы должны использовать ключевое слово constexpr вместо const верхнего уровня.

Здесь также есть ошибка gcc: g ++ отклоняет собственные примеры допустимого использования кода constexpr в стандартном проекте .

Проблема заключается в том, что ваша программа на C ++ может быть загружена в любой точке памяти, и поэтому адрес глобального кодового кода может отличаться при каждом запуске программы.Что произойдет, если вы запустите программу дважды?Очевидно, что var находится в двух разных местах.

Что еще хуже, в вашем примере вы берете адрес переменной в стеке!посмотри на это:

Genracodicetagpre

Если main вызывает myfunction (3), то в разных местах создаются 3 myvars.Во время компиляции невозможно даже узнать, сколько создано многих myvar, не говоря уже о точных местоположениях.

Наконец: объявление переменной как var означает: «Я обещаю» и не нет означает, что это константа времени компиляции.См. Этот пример:

Genracodicetagpre
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top