Почему постоянный указатель не может быть постоянным выражением?
-
29-10-2019 - |
Вопрос
Компилируется следующая программа:
общийА вот этого нет, что для меня сюрприз:
общийАльтернативный пример:
общийЯ пришел к выводу, что указатель просто не может быть константным выражением независимо от того, является ли он константным и инициализирован константным выражением.
Вопросы:
- Верно ли мое заключение?
- Если да, то почему указатель не может быть постоянным выражением?Если нет, то почему вышеуказанные программы не компилируются?
- Меняет ли что-нибудь 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.
исходный ответ:
- В C ++ 03 только интегральные выражения могут быть постоянными выражениями.
- Потому что так сказано в стандарте (естественно).
- В C ++ 0x n3290 включает примеры с использованием кода
constexpr
для указателя. Итак, то, что вы пытаетесь сделать, теперь должно быть возможным, хотя теперь вы должны использовать ключевое словоconstexpr
вместоconst
верхнего уровня.
Здесь также есть ошибка gcc: g ++ отклоняет собственные примеры допустимого использования кода constexpr
в стандартном проекте .
Проблема заключается в том, что ваша программа на C ++ может быть загружена в любой точке памяти, и поэтому адрес глобального кодового кода может отличаться при каждом запуске программы.Что произойдет, если вы запустите программу дважды?Очевидно, что var
находится в двух разных местах.
Что еще хуже, в вашем примере вы берете адрес переменной в стеке!посмотри на это:
GenracodicetagpreЕсли main вызывает myfunction (3), то в разных местах создаются 3 myvars.Во время компиляции невозможно даже узнать, сколько создано многих myvar, не говоря уже о точных местоположениях.
Наконец: объявление переменной как var
означает: «Я обещаю» и не нет означает, что это константа времени компиляции.См. Этот пример: