Является ли nullptr_t стандартным конструктивным типом? - программирование
Подтвердить что ты не робот

Является ли nullptr_t стандартным конструктивным типом?

Я не могу сказать из С++ 11 Standard, если nullptr_t имеет конструктор по умолчанию. Другими словами, допустимо следующее:

nullptr_t n; 

GCC и VС++ позволяют использовать вышеуказанный код, но clang - нет. Я не могу найти что-либо в стандарте, указав, что у него нет конструктора по умолчанию, и то, что я могу найти, предполагает, что оно должно быть. Это имеет значение для меня, потому что я пишу основную резервную реализацию nullptr для более старой поддержки компилятора и должен знать, должен ли я дать ему конструктор по умолчанию.

4b9b3361

Ответ 1

Что говорит стандарт

В стандарте говорится (18.2)

nullptr_t определяется следующим образом:

namespace std {
   typedef decltype(nullptr) nullptr_t;
}

Тип, для которого nullptr_t является синонимом, имеет характеристики, описанные в п. 3.9.1 и 4.10.

Где 3.9.1 в основном говорит, что он должен иметь тот же размер, что и void*, а 4.10 определяет правила преобразования для nullptr.

Изменить: 3.9.9 также явно заявляет, что nullptr_t является скалярным типом, что означает, что применяются ожидаемые правила инициализации для встроенных типов из 8.5:

  • Инициализация по умолчанию (nullptr_t n;), которая оставляет значение n undefined. Как правильно указал Йоханнес Шауб, это прекрасно компилируется с новейшей версией Clang.
  • Инициализация значений (nullptr_t n = nullptr_t();), которая инициализирует n до 0.

Это поведение идентично, например, int, поэтому nullptr_t определенно по умолчанию. Интересный вопрос здесь: что значит для nullptr_t иметь значение undefined? В конце дня для nullptr_t существует только одно значащее возможное значение, которое nullptr. Более того, сам тип определяется только семантикой литерала nullptr. Используются ли эти семантики для унифицированного значения?

Почему этот вопрос не имеет значения на практике

Вы не хотите объявлять новую переменную типа nullptr_t. Единственная значимая семантика этого типа уже выражается через литерал nullptr, поэтому всякий раз, когда вы будете использовать свою настраиваемую переменную типа nullptr_t, вы можете просто использовать nullptr.

Что имеет значение на практике

Единственное исключение из этого исходит из того факта, что вы можете брать параметры шаблона типа типа nullptr_t. Для этого случая полезно знать, какие значения могут преобразовываться в nullptr_t, что описано в 4.10:

Константа нулевого указателя является интегральным константным выражением (5.19) prvalue целочисленного типа, которое оценивается в 0 или prvalue типа std::nullptr_t. [...] Константа нулевого указателя интегрального типа может быть преобразована в prvalue типа std::nullptr_t.

Что в основном делает именно то, что вы ожидаете: вы можете написать

nullptr_t n = 0;    // correct: 0 is special

но не

nullptr_t n = 42;   // WRONG can't convert int to nullptr_t

Оба gcc 4.6 и Clang SVN получают это право.

Ответ 2

Пока nullptr является новым дополнением к самому языку, std::nullptr_t является просто псевдонимом неназванного типа, псевдоним, объявленный в cstddef следующим образом:

typedef decltype(nullptr) nullptr_t;

В то время как nullptr_t, являясь ключевым словом typedef, а не языком, не указан в качестве фундаментального типа, он определяется как основной тип (а не, например, как тип указателя или тип класса), Поэтому он не имеет конструктора по умолчанию, но вы все равно можете объявить переменную, как вы это делали. Ваша переменная не инициализирована, и мне интересно, что ее использование может быть и какое сообщение об ошибке вы получили от clang.

См. также здесь.