Может ли макрос NULL быть nullptr?

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

Константа нулевого указателя - это целочисленный литерал (5.13.2) с нулевым значением или 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?


person αλεχολυτ    schedule 21.02.2018    source источник
comment
Да, оно может. [[[[[[[[[[[   -  person Cheers and hth. - Alf    schedule 21.02.2018
comment
Есть ли что-то, что я не учел, да, что вы можете добавить 0 к буквальному 0.   -  person Cheers and hth. - Alf    schedule 21.02.2018
comment
Нулевой указатель значение и нулевой указатель константа - это две очень разные вещи.   -  person n. 1.8e9-where's-my-share m.    schedule 21.02.2018
comment
@ n.m: Различие между указателем, nullptr_t и литералом 0 важно, да. Но, учитывая значение типа std :: nullptr_t, вы утверждаете, что значение prvalue не является значением? Это абсурд.   -  person Cheers and hth. - Alf    schedule 21.02.2018
comment
Чтобы довести это до ума, стандартное определение: Константа нулевого указателя - это ... значение типа std :: nullptr_t (точки - это случай литерала, который также может быть).   -  person Cheers and hth. - Alf    schedule 21.02.2018
comment
@ Cheersandhth.-Alf Это значение, но не значение нулевого указателя.   -  person Angew is no longer proud of SO    schedule 21.02.2018
comment
@ Cheersandhth.-Alf Конечно, это значение типа std::nullptr_t, которое не является типом указателя, поэтому нет оснований называть его значением нулевого указателя (это вообще не значение указателя). В любом случае в предложении «Аддитивные операторы» перечислены типы, которые могут участвовать в аддитивных операторах, и std::nullptr_t не входит в их число, поэтому std::nullptr - std::nullptr недействителен независимо от того, вызываете ли вы std::nullptr значение нулевого указателя или нет.   -  person n. 1.8e9-where's-my-share m.    schedule 21.02.2018
comment
Windows говорит нет. :(   -  person Joshua    schedule 21.02.2018
comment
Связанный C ++: сравнить возвращаемое значение функции C с NULL или nullptr?   -  person Shafik Yaghmour    schedule 22.02.2018


Ответы (4)


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

Ссылка:

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

7.11 / 1 в N4659, подчеркиваю мой

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

person Baum mit Augen    schedule 21.02.2018
comment
@ Cheersandhth.-Alf Это значение хорошо, но стандарт явно говорит о значениях нулевых указателей как о значениях указателей. nullptr не является указателем. - person Baum mit Augen; 21.02.2018
comment
@ Cheersandhth.-Alf - Нет, он заслуживает одобрительного голосования, потому что в стандартном тексте значение нулевого указателя рассматривается как термин, а не просто значение. И если вы хотите углубиться в прошлые встречи, не начинайте обвинять других в том, что они стали личными. - person StoryTeller - Unslander Monica; 21.02.2018
comment
Любая константа - это значение. Просто нет никаких требований, чтобы nullptr поддерживал добавление. Однако литерал 0 поддерживает добавление, а стандарт описывает результат добавления времени компиляции 0 к 0. - person Cheers and hth. - Alf; 21.02.2018
comment
@ Cheersandhth.-Alf Если я ошибаюсь, не могли бы вы дать мне лучшее объяснение, чем Константа - это значение? Многие вещи являются значениями в C ++, и насколько это актуально для вопроса, является ли nullptr значением нулевого указателя, мне пока не ясно. - person Baum mit Augen; 21.02.2018
comment
@BaummitAugen - возможно, [basic.compound] / 3, чтобы лучше довести эту точку до дома? - person StoryTeller - Unslander Monica; 21.02.2018
comment
@BaummitAugen: Я думаю, что ответ С.М. хорош. Также мой собственный в комментариях к вопросу. - person Cheers and hth. - Alf; 21.02.2018
comment
@ Cheersandhth.-Alf Извините, но я не вижу, как nullptr сам по себе не является ни значением указателя, ни указателем. Таким образом, арифметические операции не применимы к nullptr правильно, если это не значение нулевого указателя неверно. - person Baum mit Augen; 21.02.2018
comment
@StoryTeller Спасибо за ссылку, но я думаю, что это более актуально для доказательства того, что указатель может иметь значение нулевого указателя, а не столько для определения того, что это на самом деле. - person Baum mit Augen; 21.02.2018
comment
@ Cheersandhth.-Alf C ++ 17 7.11 / 1 Константа нулевого указателя - это целочисленный литерал (5.13.2) с нулевым значением или prvalue типа std::nullptr_t. Константа нулевого указателя может быть преобразована в тип указателя; результатом является значение нулевого указателя этого типа, которое можно отличить от любого другого значения указателя на объект или типа указателя на функцию. Такое преобразование называется преобразованием нулевого указателя. Кажется, это довольно четко указывает на то, что nullptr (или любое другое prvalue типа std::nullptr_t) не значение нулевого указателя. - person Angew is no longer proud of SO; 21.02.2018
comment
@Angew: Спасибо, но это уже было процитировано OP. В нем говорится, что нулевой указатель является, помимо прочего, значением типа std::nullptr. То, что это prvalue, подтверждает, что это ценность. - person Cheers and hth. - Alf; 21.02.2018
comment
@ Cheersandhth.-Alf Не может быть и речи о том, является ли это значение значением, но где говорится, что это значение нулевого указателя? - person Baum mit Augen; 21.02.2018
comment
+1 @BaummitAugen: Я нашел определение C ++ 17 §7.11 / 1, и по этому определению вы правы. Прости. Я думаю, тебе стоит процитировать это. - person Cheers and hth. - Alf; 21.02.2018
comment
@ Cheersandhth.-Alf Это именно тот абзац, который я уже цитировал, если только там что-то не изменилось между N4659 и C ++ 17. Я не покупал последнее, поэтому, если это уместно, спасибо за указание на разницу. - person Baum mit Augen; 21.02.2018
comment
Мне нужны новые глаза. Извините за путаницу! - person Cheers and hth. - Alf; 21.02.2018

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

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

Может ли макрос NULL быть nullptr?

Да, потому что nullptr - литерал нулевого указателя.

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

person eerorika    schedule 21.02.2018

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

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

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

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

person n. 1.8e9-where's-my-share m.    schedule 21.02.2018

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

person S.M.    schedule 21.02.2018
comment
так что 8.5.6 / 7 не применяется к nullptr, потому что это не значение нулевого указателя? (удалил этот комментарий после прочтения ответа Баумса и репост после прочтения обсуждения ниже этого ответа;) - person 463035818_is_not_a_number; 21.02.2018
comment
Если nullptr относится к типу std::nullptr_t, а не к типу указателя, как это литерал указателя? Возможно, вы захотите немного перефразировать, чтобы быть более точным. - person StoryTeller - Unslander Monica; 21.02.2018
comment
@ user463035818 Да, вы правы. prvalue («чистое» r-значение) - это r-значение, которое не является xvalue. [Пример: результатом вызова функции, тип возвращаемого значения которой не является ссылкой, является prvalue] - скопировано отсюда stackoverflow.com/questions/3601602/ - person S.M.; 21.02.2018
comment
@StoryTeller NULL - это константа нулевого указателя, определяемая реализацией. nullptr_t - это тип литерала нулевого указателя nullptr, например char - это тип символьного литерала 'a' или const char const * - тип строкового литерала "abc". - person S.M.; 21.02.2018
comment
Не думаю, что ты получил то, к чему я стремился. Литералы - это типизированные значения. Поскольку nullptr_t не является типом указателя, nullptr не может быть литералом указателя. - person StoryTeller - Unslander Monica; 21.02.2018
comment
@StoryTeller Я не думаю, что стандарт может быть более ясным по этому поводу: Литерал указателя - это ключевое слово nullptr. Это значение типа std :: nullptr_t. [Примечание: std :: nullptr_t - это отдельный тип, который не является ни типом указателя, ни ... Очевидно, что отсутствие типа указателя не мешает nullptr быть литералом указателя. - person eerorika; 21.02.2018
comment
@ user2079303 - Ну, хватит для согласованности с другими литералами prvalue. Это не указатель, а литерал указателя !? Какого черта. - person StoryTeller - Unslander Monica; 21.02.2018