Может ли NULL-макрос быть нулевым?

Согласно проекту стандарта N4713 (7.11/1):

Константа нулевого указателя представляет собой целочисленный литерал (5.13.2) со значением 0 или prvalue типа std::nullptr_t.

и 21.2.3/2:

Макрос NULL представляет собой константу нулевого указателя, определяемую реализацией.

следует, что NULL можно определить как nullptr. То же самое упоминается в cppreference:

#define NULL 0
//since C++11
#define NULL nullptr

В то же время в пункте "Аддитивные операторы" говорится (8.5.6/7):

Если значение 0 добавляется или вычитается из значения нулевого указателя, результатом является значение нулевого указателя. Если два значения нулевого указателя вычитаются, результат сравнивается с значением 0 преобразованным в тип std::ptrdiff_t.

Следовательно, следующий код должен быть действительным:

0 + nullptr; 
nullptr - nullptr; 

но из-за отсутствия операторов + / - для std::nullptr_t код недействителен.

Есть ли что-то, что я не принимал во внимание, или NULL макрос не может быть фактически определен как nullptr?

Ответ 1

Хотя nullptr является константой нулевого указателя, это не значение нулевого указателя. Последний является значением некоторого типа указателя, который std::nullptr_t не является.

Ссылка:

Константа нулевого указателя представляет собой целочисленный литерал (5.13.2) со значением 0 или prvalue типа std::nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является нулевое значение указателя этого типа и отличается от любого другого значения указателя объекта или типа указателя функции. Такое преобразование называется преобразованием нулевого указателя. [...]

7.11/1 в N4659, подчеркнуть мою

Таким образом, NULL действительно может быть nullptr без предоставления арифметических операторов.

Ответ 2

nullptr - литерал нулевого указателя, и хотя результат преобразования nullptr в тип указателя является значением нулевого указателя, сам nullptr не имеет тип указателя, а тип std::nullptr_t. Арифметика работает, если вы преобразуете nullptr в тип указателя:

0 + (int*)nullptr; 
(int*)nullptr - (int*)nullptr;

Может ли NULL-макрос быть нулевым?

Да, поскольку nullptr является литералом с нулевым указателем.

Обратите внимание, что до C++ 11 все литералы нулевого указателя в C++ также были целыми литералами, поэтому этот плохой код: char c = NULL; используется на практике. Если NULL определяется как nullptr, этот код больше не работает.

Ответ 3

Для добавления оба операнда должны иметь арифметический или неперечисленный тип перечисления, или один операнд должен быть указателем на полностью определенный тип объекта, а другой должен иметь интегральный или неперечисленный тип перечисления.

Для вычитания должно выполняться одно из следующих условий:
(2.1) оба операнда имеют арифметический или неперечисленный тип перечисления; или же
(2.2) оба операнда являются указателями на cv-квалификационные или cv-неквалифицированные версии одного и того же полностью определенного типа объекта; или же
(2.3) левый операнд является указателем на полностью определенный тип объекта, а правый операнд имеет интегральный или неперечисленный тип перечисления.

std::nullptr_t является ничем из этого, поэтому std::nullptr не может участвовать в аддитивных операциях.

Обратите внимание, что даже не могут принимать значения всех указателей. Например, значения указателя функции и значения указателя void не могут, даже если они могут быть нулевым значением указателя.

Ответ 4

Ключевое слово nullptr обозначает литерал-указатель. Это prvalue типа std::nullptr_t. Существуют неявные преобразования от значения nullptr к нулевому указателю любого типа указателя и любого указателя на тип члена. nullptr сам по себе не является значением указателя или указателем. Таким образом, арифметические операции не применимы к nullptr.