Подтвердить что ты не робот

Как отличить 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 для этого?

4b9b3361

Ответ 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, или что-то еще подобное.