|
|
||||||
Как компилятор обрабатывает член класса static constexpr const char*16.09.2016, 12:05. Показов 5547. Ответов 14
Метки нет (Все метки)
Привет!
Наткнулся на непонятный момент
constexpr не компилируется. Вопрос - как компилятора без линкера разруливает это дело, ведь constexpr value ему нужен на этапе компиляции? Если он это пережевывает, почему тогда constexpr необходим?
1
|
||||||
| 16.09.2016, 12:05 | |
|
Ответы с готовыми решениями:
14
Static член класса |
|
What a waste!
1610 / 1302 / 180
Регистрация: 21.04.2012
Сообщений: 2,733
|
|
| 16.09.2016, 22:28 | |
|
Kastaneda, судя по сообщениям компилятора, const char* - не "интегральный" тип, и видимо в этом загвоздка - совмещать объявление статического члена класса и его инициализацию можно только для "интегральных" типов; в то время как при использовании constexpr инициализация необходима при объявлении.
1
|
|
|
19497 / 10102 / 2461
Регистрация: 30.01.2014
Сообщений: 17,808
|
||
| 17.09.2016, 00:17 | ||
|
1
|
||
|
Игогошка!
1801 / 708 / 44
Регистрация: 19.08.2012
Сообщений: 1,367
|
||
| 17.09.2016, 14:33 | ||
|
2. А зачем ему линкер? Для таких объектов у компилятора адрес - это просто какая-то релокация. Он ее потом отправит в elf и все. А линкер дальше будет с ее использованием по соответствующему выражению адрес считать. Компилятору же нужно только знать, что эта релокация - константа.
3
|
||
|
19497 / 10102 / 2461
Регистрация: 30.01.2014
Сообщений: 17,808
|
||
| 17.09.2016, 18:16 | ||
|
1
|
||
|
Вездепух
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
|
||||||||||||
| 20.09.2016, 06:14 | ||||||||||||
Сообщение было отмечено HighPredator как решение
Решение
pi не может быть известным на стадии компиляции. Более того, это значение даже в те времена в Unix не обязательно было известно даже на стадии линковки, а могло оказаться известным только на стадии загрузки (например, для глобальных объектов, определенных в shared objects). То есть конкретное значение адресной константы в общем случае может быть даже не линкером, а только загрузчиком в момент начала выполнения.По этой причине спецификация адресных констант в С была специально подогнана под возможности загрузчиков. А именно, в С адресные константы выступают как константы только в инициализаторах и только либо сами собой, либо с прибавлением к адресной константе (или вычитанием из нее) какого-то смещения, известного на стадии компиляции (что разрешает в т.ч. применение операторов [] и -> в комбинации с & для формирования новых адресных констант). Другими словами, адресные константы в С могут быть использованы как константы только для целей относительной адресации.То есть в рамках спецификации, нельзя написать
(size_t) pi на стадии компиляции. Так вот спецификация constexpr в С++ совсем не далеко уходит от этих ограничений, пришедших в С++ из С. Фактически, все, чего вы добиваетесь указанием constexpr в этом объявлении указателя, это превращение в constexpr таких выражений, как PTR[5]. Для этого инициализатор PTR должен быть виден компилятору, т.е. присутствовать в объявлении. Ясно, что для определения значения PTR[5] в таком случае компилятору совсем не нужно знать конкретного значения PTR.Любые же попытки "выковырять" из PTR его численное значение на стадии компиляции (или как-то еще завязаться на абсолютную точку в памяти, куда он указывает) обречены на провал, даже несмотря на то, что PTR объявлен как constexpr.
7
|
||||||||||||
|
|
|
| 20.09.2016, 09:26 | |
|
Если вернуться к изначальному вопросу. Почему без constexpr не компилируется - уже ответили: инициализатор должен быть не в теле класса, а там, где объявлено само тело статического поля. Т.е. где-то вне тела класса должно быть написано
C++ const char* Foo::PTR = "value";
0
|
|
|
Вездепух
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
|
||
| 20.09.2016, 09:46 | ||
static constexpr разрешается писать инициализатор прямо в теле класса. Это необходимо для того, чтобы реализовать вычисления на стадии компиляции. В вычислениях на стадии компиляции и заключается вся идея constexpr. В данном случае инициализатор необходим для того, чтобы на стадии компиляции вычислять выражения вида PTR[5].При этом определением указателя PTR такое объявление не становится, даже несмотря на наличие инициализатора. Если где-то в коде PTR окажется использованным как lvalue, то придется его еще где-то определить. Инициализатор в определении повторять не надо.
0
|
||
|
|
|
| 20.09.2016, 15:24 | |
|
Я правильно понимаю ситуацию? Сначала (условно в C++98) разрешили писать инициализатор в теле класса ради того, чтобы static-поле класса можно было, грубо говоря, использовать в качестве размерности НЕавтоматического массива. Для указателей подобной необходимости не было, а потому не разрешали. Теперь (с C++11) из-за constexpr появилась необходимость использовать указатель (как rvalue) в других constexpr выражениях в НЕавтоматических местах, растущих от других constexpr'ов. Типа того?
0
|
|
|
Вездепух
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
|
||
| 21.09.2016, 08:34 | ||
Сообщение было отмечено HighPredator как решение
РешениеВ С++98 (и С++03) возможность использования static const членов класса в качестве констант времени компиляции понимали (отсюда разрешение на указание инициализаторов для целых и enum типов), но это возможность все равно рассматривалась, как "вторичная". Например, правила ODR в С++98 формально требовали отдельного определения такого члена класса, если он использовался (used) в программе. При этом не придавалось никакого значения тому, как он использовался. Даже если static const использовался только как rvalue (напр. только для задания размера массива), все равно наличие определения безусловно требовалось спецификацией языка. Хотя понятно, что с точки зрения здравого смысла такое определение было никому не нужно. (Многие компиляторы натуральным образом не следили за соблюдением этого требования, если такая константа использовалась только как rvalue).В С++11 возможность использования таких констант именно и только как констант времени компиляции уже вышла на первый план. Правила ODR были модифицированы и требуют отдельного определения static const членов класса только если они odr-используются (odr-used) в программе, т.е. если они где-то используются именно как lvalue. А если такая константа используется только как rvalue, то делать для нее отдельное определение больше не требуется.Но дальше расширять функциональность static const не стали (возможно, там скрыты какие-то конфликты), т.е. указывать инициализаторы для static const прямо в классе по-прежнему можно только для целых и enum типов. Вместо этого для создания констант времени компиляции ввели совершенно новый механизм constexpr. Для constexpr констант указывать инициализаторы прямо в классе можно всегда, независимо от типа. Понятно, что наличие видимых отовсюду инициализаторов совершенно необходимо для того, чтобы обрабатывать такие константы на стадии компиляции.
3
|
||
|
|
||
| 21.09.2016, 16:12 | ||
|
0
|
||
|
Вездепух
12936 / 6803 / 1821
Регистрация: 18.10.2014
Сообщений: 17,214
|
||||||||||||
| 22.09.2016, 22:19 | ||||||||||||
|
В С++17 вводится понятие inline variable. И можно будет писать так
S::x является ее определением. Переменную можно использовать как lvalue, и при этом какого-то дополнительного определения для нее делать не надо (и нельзя).Далее, constexpr константы в С++17 становятся частным случаем inline variable. При этом, для сохранения обратной совместимости, писать отдельное "определение" для такой константы разрешается, но является deprecated
5
|
||||||||||||
| 22.09.2016, 22:19 | |
|
Помогаю со студенческими работами здесь
15
constexpr static functions
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога
Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
|
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
|
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога
В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
|
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога
Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
|
|
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога
Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
|
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога
Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
|
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования.
Часть библиотеки BedvitCOM
Использованы. . .
|
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога
SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
|