Как отличить 0 от других целых чисел при инициализации nullptr_t?
Как я понимаю, std::nullptr_t
может быть инициализирован из nullptr
, а также из 0
. Но в то же время третья инициализация ниже не работает, несмотря на то, что 5
имеет тот же тип, что и 0
:
#include <memory>
int main()
{
std::nullptr_t null1=0;
std::nullptr_t null2=nullptr;
std::nullptr_t null3=5; // error: cannot convert ‘int’ to ‘std::nullptr_t’ in initialization
}
Как это работает? То есть как стандартная библиотека выделяет 0
из 5
во время компиляции, если эти литералы не являются аргументами шаблона?
Можно создать пользовательский класс, который бы аналогичным образом отличал аргументы своего конструктора во время компиляции, а не используя std::nullptr_t
для этого?
Ответы
Ответ 1
A nullptr_t
может быть присвоено только значение nullptr
или 0
, которое неявно преобразуется.
Согласно N4296 (стр .86):
4.10 Преобразования указателей
Константа нулевого указателя представляет собой целочисленный литерал со значением нольили prvalue типа std::nullptr_t
. Константа нулевого указателя может быть преобразован в тип указателя; результатом является значение нулевого указателя этот тип и отличается от любого другого значения объекта указатель или тип указателя функции. [...] Константа нулевого указателя интегральный тип может преобразовываться в prvalue типа std::nullptr_t
.
Вы можете не создать аналогичный тип внутри С++ самостоятельно.
std::nullptr_t
реализуется как встроенный тип, и его различные свойства применяются компилятором.
EDIT: Исправлен абзац для встроенных типов. Спасибо Якку!
Ответ 2
N3337 [conv.ptr]/1:
Константа нулевого указателя представляет собой целочисленное константное выражение prvalue целочисленного типа, которое вычисляет ноль или значение типа std::nullptr_t
. Константа нулевого указателя может быть преобразована в тип указателя; результатом является нулевое значение указателя этого типа и отличается от любого другого значения указателя объекта или тип указателя функции. Такое преобразование называется преобразованием нулевого указателя. Два значения нулевого указателя одинаковый тип должен сравниваться. Преобразование константы нулевого указателя в указатель на тип cv-qual одно преобразование, а не последовательность преобразования указателя, за которой следует преобразование квалификации. Константа нулевого указателя интегрального типа может быть преобразована в prvalue типа std::nullptr_t
.
0
- это константа нулевого указателя интегрального типа, поэтому ее можно преобразовать в значение класса std::nullptr_t
. 5
не является константой нулевого указателя, поэтому не может быть.
Ответ 3
как стандартная библиотека отличает 0 от 5 во время компиляции, если эти литералы не являются аргументами шаблона?
Это вообще не имеет никакого отношения к стандартной библиотеке, nullptr_t
- это встроенный тип, известный компилятору, и, очевидно, компилятор знает разницу между 5
и 0
Можно ли создать пользовательский класс, который бы аналогичным образом отличал аргументы его конструктора во время компиляции, а не используя std::nullptr_t
для этого?
В общем случае нет.
Вы можете написать тип, который может быть инициализирован из 0
, а не из 5
, заставив его принять аргумент типа указателя, потому что 0
- действительная константа нулевого указателя, а 5
- нет. Но вы не можете написать тип, который может быть создан из 3
, а не из 5
, или что-то еще подобное.