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

Почему "bool c = nullptr;" компилирует (С++ 11)?

Я не понимаю, почему следующий код компилирует?

int main()
{
     //int a = nullptr;  // Doesn't Compile
     //char b = nullptr; // Doesn't Compile
       bool c = nullptr; // Compiles

       return 0;
}

тогда как в разделе комментариев нет.


Я уже прошел и .

Оба bool и nullptr являются ключевыми словами, поэтому что уникально для других типов данных?

4b9b3361

Ответ 1

По той же причине, что и

if( p ) { ... }

компилирует: любое значение базового типа неявно преобразуется в boolean, при преобразовании 0 в false и любом другом значении в true.

Первоначально значения базового типа должны были преобразовываться в bool для совместимости с C. C первоначально не имел тип bool, но любое числовое выражение могло бы использоваться как логическое (с соглашением 0 == false). И теперь мы попадаем в спутник обратной совместимости. nullptr должен поддерживать идиоматические конструкции, такие как if(p), особенно для случаев, когда старый литерал кода 0 или NULL заменяется на nullptr. Например. такой код, как if(p), может быть вызван расширением макроса или кодом шаблона.


Добавление: техническое объяснение того, почему nullptr не преобразуется, например. int.

Так как nullptr неявно преобразуется в bool, а bool (к сожалению) неявно преобразуется в int, можно ожидать, что nullptr также должен преобразовать в int. Но точка nullptr заключается в том, что она должна вести себя как значение указателя. И хотя указатели неявно преобразуются в bool, они не преобразуются неявно в числовые типы.

Упорядочение такого ограничения для пользовательского типа, однако, не является полностью простым. Преобразование operator bool будет вызываться для преобразования в int, если оно присутствует. Одним из решений С++ 11 для ограничения этого ограничения является преобразование оператора преобразования, ограниченного a std::enable_if следующим образом:

#include <type_traits>  // std::enable_if, std::is_same

struct S
{
    template< class Type >
    operator Type* () const { return 0; }

    template<
        class Bool_type,
        class Enabled = typename std::enable_if<
            std::is_same<Bool_type, bool>::value, void
            >::type
        >
    operator Bool_type () const { return false; }
};

auto main() -> int
{
    bool const              b   = S();      // OK.
    double const*  const    p   = S();      // OK.
    int const               i   = S();      // !Doesn't compile.
}

Ответ 2

С++ 11 §4.12 Логические преобразования

Значение арифметики, неперечисленного перечисления, указателя или указателя на тип члена может быть преобразовано в prvalue типа bool. Нулевое значение, значение нулевого указателя или значение указателя нулевого элемента преобразуется в false; любое другое значение преобразуется в true. Значение типа std::nullptr_t может быть преобразовано в prvalue типа bool; результирующее значение false.

Верно, что nullptr является ключевым словом, но это литерал нулевого указателя, а не ту же роль, что и bool. Подумайте о булевых литералах, true и false также являются ключевыми словами.

Ответ 3

В http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#654 Джейсон Мерриль утверждает

Все, что мы можем сделать с помощью произвольного указателя, мы также должны иметь отношение к nullptr_t.

Я думаю, что следующий (слегка искусственный) пример поддерживает этот аргумент (хотя я не совсем уверен, был ли он предназначен для этого случая)

template<typename T, typename P>
void safeProcess(T pointer, P &processor) {
  bool isNonNull(pointer);
  if(isNonNull) {
    processor.process(pointer);
  }
}

Что позволит передавать nullptr вместе с другими типами указателей, совместимыми с тем, что принимает processor.process.

Ответ 4

С++ 11 исправляет это, вводя новое ключевое слово, чтобы служить в качестве выделенной константы нулевого указателя: nullptr. Он имеет тип nullptr_t, который неявно конвертируется и сопоставим с любым типом указателя или типа указателя на член. Он не является неявно конвертируемым или сопоставимым с целыми типами, за исключением bool. Хотя в первоначальном предложении указано, что значение rvalue типа nullptr не должно быть конвертируемым в bool, рабочая группа основного языка решила, что такое преобразование было бы желательно для согласованности с обычными типами указателей. Предлагаемые изменения в формулировке были единогласно проголосованы в рабочем документе в июне 2008 года. [2]

Для соображений обратной совместимости 0 остается действительной константой нулевого указателя.

char *pc = nullptr;     // OK
int  *pi = nullptr;     // OK
bool   b = nullptr;     // OK. b is false.
int    i = nullptr;     // error