C ++ nullptr 구현은 어떻게 작동합니까? const {return 0;}

어떻게 nullptr작동 하는지 궁금 합니다. 표준 N4659 및 N4849는 다음과 같이 말합니다.

  1. 형식이 있어야합니다 std::nullptr_t.
  2. 당신은 그 주소를 취할 수 없습니다;
  3. 포인터와 멤버에 대한 포인터로 직접 변환 될 수 있습니다.
  4. sizeof(std::nullptr_t) == sizeof(void*);
  5. 로의 변환 boolfalse;
  6. 그것의 값은와 동일하게 정수형으로 변환 될 수 (void*)0있지만, 거꾸로되지는 않는다;

따라서 기본적으로와 같은 의미의 상수 (void*)0이지만 유형이 다릅니다. std::nullptr_t내 장치 에서 구현을 찾았으며 다음과 같습니다.

#ifdef _LIBCPP_HAS_NO_NULLPTR

_LIBCPP_BEGIN_NAMESPACE_STD

struct _LIBCPP_TEMPLATE_VIS nullptr_t
{
    void* __lx;

    struct __nat {int __for_bool_;};

    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) {}
    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) {}

    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const {return 0;}

    template <class _Tp>
        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
        operator _Tp* () const {return 0;}

    template <class _Tp, class _Up>
        _LIBCPP_INLINE_VISIBILITY
        operator _Tp _Up::* () const {return 0;}

    friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) {return true;}
    friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) {return false;}
};

inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() {return nullptr_t(0);}

#define nullptr _VSTD::__get_nullptr_t()

_LIBCPP_END_NAMESPACE_STD

#else  // _LIBCPP_HAS_NO_NULLPTR

namespace std
{
    typedef decltype(nullptr) nullptr_t;
}

#endif  // _LIBCPP_HAS_NO_NULLPTR

그래도 첫 번째 부분에 더 관심이 있습니다. 1-5 점을 만족시키는 것 같지만 왜 하위 클래스 __nat 및 관련 클래스가 있는지 모르겠습니다. 또한 통합 변환에서 왜 실패하는지 알고 싶습니다.

struct nullptr_t2{
    void* __lx;
    struct __nat {int __for_bool_;};
     constexpr nullptr_t2() : __lx(0) {}
     constexpr nullptr_t2(int __nat::*) : __lx(0) {}
     constexpr operator int __nat::*() const {return 0;}
    template <class _Tp>
         constexpr
        operator _Tp* () const {return 0;}
    template <class _Tp, class _Up>
        operator _Tp _Up::* () const {return 0;}
    friend  constexpr bool operator==(nullptr_t2, nullptr_t2) {return true;}
    friend  constexpr bool operator!=(nullptr_t2, nullptr_t2) {return false;}
};
inline constexpr nullptr_t2 __get_nullptr_t2() {return nullptr_t2(0);}
#define nullptr2 __get_nullptr_t2()

int main(){
    long l  = reinterpret_cast<long>(nullptr);
    long l2 = reinterpret_cast<long>(nullptr2); // error: invalid type conversion
    bool b  = nullptr; // warning: implicit conversion
                       // edditor error: a value of type "std::nullptr_t" cannot be used to initialize an entity of type "bool"
    bool b2 = nullptr2;
    if (nullptr){}; // warning: implicit conversion
    if (nullptr2){};
};


답변

nullptr의 작동 방식을 알고 싶습니다.

그것은 가능한 가장 간단한 방법으로 작동합니다 : fiat . C ++ 표준 이 작동 한다고 말했기 때문에 작동하며 C ++ 표준은 구현 이 그러한 방식으로 작동하도록 해야한다고 말했기 때문에 작동 합니다 .

C ++ 언어의 규칙을 사용하여 구현 하는 것이 불가능 하다는 것을 인식하는 것이 중요합니다 std::nullptr_t. 유형의 널 포인터 상수에서 포인터로의 변환은 std::nullptr_t사용자 정의 변환이 아닙니다. 즉, 널 포인터 상수에서 포인터로 이동 한 다음 사용자 정의 변환을 통해 다른 유형으로 단일 암시 적 변환 순서로 모두 변환 할 수 있습니다.

nullptr_t클래스로 구현하면 불가능합니다 . 변환 연산자는 사용자 정의 변환을 나타내며 C ++의 암시 적 변환 시퀀스 규칙은 이러한 시퀀스에서 둘 이상의 사용자 정의 변환을 허용하지 않습니다.

그래서 당신이 게시 한 코드는 근사치입니다 std::nullptr_t.하지만 그 이상입니다. 합법적 인 유형의 구현이 아닙니다. 이것은 컴파일러가에 대한 적절한 지원을 제공하기 전에 이전 버전의 컴파일러 (이전 버전과의 호환성을 위해 남아 있음) 일 것입니다 std::nullptr_t. 당신은 그 사실이 볼 수 #defines의 nullptrC ++ (11)가 말하는 동안, nullptrA는 키워드 가 아닌 매크로.

C ++는 구현할 수 없습니다 std::nullptr_tC ++ 구현되지 수있는 것처럼, int또는 void*. 구현 만이 그러한 것들을 구현할 수 있습니다. 이것이 “기본 유형”이되는 것입니다. 언어 의 일부입니다 .


값은 (void *) 0과 동일하게 정수 유형으로 변환 될 수 있지만 역방향은 아닙니다.

널 포인터 상수에서 정수 유형으로의 암시 적 변환없습니다 . 0정수형으로 의 변환이 있지만 정수 리터럴 0이기 때문에 정수입니다.

nullptr_t를 통해 정수 유형 으로 캐스트 할 수 reinterpret_cast있지만 암시 적으로 포인터 및로만 변환 할 수 있습니다 bool.