Переменные constexpr и константные выражения

Задания раздела 2.4.4 
2.32. Допустим ли следующий код? Если нет, то как его исправить?
int null=0, *p=null;

Константное выражение - это выражение, которое вычисляется во время компиляции и не может измениться.
Литерал - это константное выражение.
Константый объект, инициализируемый константным выражением (литералом например) является константным выражением.
const int i=1024; // константное выражение
const int p=i+1; // константное выражение
Неконстантый объект не может быть константным выражением. Например:
int i=1024; // хоть 1024 и литерал, но i - не константа

p105_ex2-4-4

Если константная переменная инициализирована результатом выполнения функции, то это неконстантное выражение, потому что значение инициализатора неизвестно во время выполнения.
Есть способ проверить константное выражение или неконстантное с помощью слова constexpr. Как это использовать и зачем - мне пока что непонятно. Можно использовать constexpr для определения константы:
constexpr int i=1024; //i является константой и переопределить её нельзя.
Существует возможность определения константного выражения функцией, но функция должна быть constexpr (и быть простой, чтобы по-быстрому компилироваться).
Это какая-то особая магия, о которой говорится сейчас, но не говорится к чему это всё. Я чувствую чары и глубокую невидимую яму перед собой.
Все типы, которые я использовал до сих пор являются литеральными (арифметические, указатели и ссылки), но уже упомянутые типы string и классы (Sales_item) не являются литеральными и не могут использоваться в выражении constexpr.
Используемые для инициализации ссылок и указателей объекты с помощью constexpr строго ограничены. Указатель constexpr можно инициализировать литералом nullptr или литералом 0 (константным выражением), или связать с объектом, находящимся по фиксированному адресу.
Но определенные в функции переменные обычно не имеют фиксированного адреса (пока что просто как данность), поэтому для инициализации указателя выражением constexpr не годятся (только если функция не определяет переменные, которые доступны во время нескольких вызовов функции - это уже другое дело и связывать с указателем constexpr допускается). Если адрес объекта определен вне функции, то это - допустимое для указателя значение.
А теперь ахтунг:
Constexpr относится к указателю, а не типу
constexpr int* p=nullptr; // p - константный указатель (const верхнего уровня)

Жменька вполне легких и ожидаемых примеров. Для нормальной компиляции переменные i и j должны быть определены вне любой функции (яма темна и глубока, а фонарика нет).
constexpr int *npt=nullptr; // то же самое что и выше
int j=0;
constexpr int i=42; /* обычная константа, инициализировання литералом (const верхнего уровня) */
constexpr const int *p=&i; // константный указатель на константный объект
constexpr int *p1=&j; // константный указатель
Простая программа. Писать ничего не буду, потому что одни сплошные догадки и стыдно. На самом деле не стыдно, вроде бы как всё просто - main() - функция и определенные в функции переменные не имеют постоянного адреса (Господи, чем я занимался с указателями в предыдущих разделах, а?). Constexpr привносит в жизнь что-то новое, а разум не готов это понять.
#include <iostream>
int j=0;
int main ()
{
constexpr int *p1=&j;
std::cout << "p=" <<p1 << std::endl;
*p1=2;
std::cout << "j="<< j << " "<< &j;
return(0);
}
Я ничего не понял про constexpr кроме нескольких занятных фактов, которые просто запомню. Дальше будет видно к чему это всё. Обычна сваленная в кучу информация без конкретики. О чём свидетельствует следующее задание.
2.32. Допустим ли следующий код? Если нет, то как его исправить?
int null=0, *p=null;

Вот так исправить:
#include <iostream>
int main ()
{
int null=0, *p=NULL;
std::cout << null <<" " <<p ;
return(0);
}

Добавить комментарий