【ローミングC++11】nullptrとstd::nullptr_t


C/C++には、一般的なマクロ:NULLがあります.C言語では一般的に(void*)0と定義され、0と定義されることも可能であり、C++ではNULLは0でなければならない.
次のようになります.
#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0             // C++
    #else
        #define NULL ((void *)0)   // C                C  (C99)       “//”  
    #endif
#endif

このような定義は、うっかりすると誤解を招きます.
void Func(char*)
{
    std::cout << "Func(char*)" << std::endl;
}

void Func(int)
{
    std::cout << "Func(int)" << std::endl;
}

int main()
{
    Func(NULL); // Func(int)
    return 0;
}

空のポインタをNULLで表すことが多いので、上のコードは最初のFuncを呼び出すと勘違いされがちですが、実際にはNULLはC++で0なので2番目を呼び出すことになります.
頭がはっきりしているときは、これは問題ではありませんが、コード量が増えるにつれて、私たちはこの細部に集中することが難しくなり、この問題に気づいても、不要な心の負担になります.
nullptrは運に応じて生まれた.
nullptrはstd::nullptr_tタイプの(constexpr)変数.std::nullptr_tは、クラスのメンバー関数ポインタを含む任意のポインタに明示的または暗黙的に変換できますが、他の任意のタイプに明示的または暗黙的に変換することはできません.
nullptrを使用すると、この誤解を解消することができます.例えば、上記のコードは、Func(nullptr)を呼び出してFunc(char*)を必ず出力します.
実際には、C++11でNULLを再定義したほうが効果的ですが、すでに多くのコードがNULLを使用していることを考慮して、以前のコードが使用可能になるようにnullptrを追加したのかもしれません.
最後に、詳細を補足します.
1)std::nullptr_tは算術式には使用できません.すなわち、+、-、*などは使用できません.
2)std::nullptr_tは関係式に使用できます.2つのstd::nullptr_tタイプの変数は、=、<=、>=演算を行うとtrueを返し、他の関係演算はfalseを返す.
3)nullptrは&(アドレスを取る)演算ができません.
コンパイラがC++11をサポートしていない場合は、nullptrをC++98/C++03でシミュレートできます.
//    C++11    
class nullptr_tt
{
public:
    template<class _Tx> operator _Tx*() const { return 0; }
    template<class _Tx, class _Ty> operator _Ty _Tx::*() const{ return 0; }
private:
    void operator& () const; //       
};

const nullptr_tt nullptr;