標準N4713(7.11/1)のドラフトによると:
NULLポインター定数は、値がゼロの整数リテラル(5.13.2)または
std::nullptr_t
型のprvalueです。
および21.2.3/2:
マクロ
NULL
は、実装定義のNULLポインター定数です。
NULL
はnullptr
として定義できます。 cppreference にも同じことが記載されています:
#define NULL 0
//since C++11
#define NULL nullptr
同時に、「加算演算子」節は(8.5.6/7)と言います:
値
0
がNULLポインター値に加算または減算されると、結果はNULLポインター値になります。 2つのNULLポインター値を減算すると、結果は0
型に変換されたstd::ptrdiff_t
値と等しくなります。
したがって、次のコードは有効である必要があります。
0 + nullptr;
nullptr - nullptr;
ただし、std::nullptr_t
の+/-演算子がないため、 コードは無効です です。
私が考慮しなかったものや、NULL
マクロを実際にnullptr
として定義できないものはありますか?
nullptr
はnullポインターconstantですが、nullポインターvalue。後者は、いくつかのポインタ型の値ですが、std::nullptr_t
はそうではありません。
参照:
NULLポインター定数は、値がゼロの整数リテラル(5.13.2)または
std::nullptr_t
型のprvalueです。 nullポインター定数はポインター型に変換できます。結果はその型のnullポインター値であり、オブジェクトポインターまたは関数ポインター型の他のすべての値と区別できます。このような変換は、NULLポインター変換と呼ばれます。 [...]
N4659の7.11/1、鉱山を強調
したがって、算術演算子を指定しなくても、NULL
は実際にnullptr
になります。
nullptr
はNULLポインターリテラルであり、nullptr
をポインター型に変換した結果はNULLポインター値ですが、nullptr
自体はポインター型ではありませんが、タイプstd::nullptr_t
。 nullptr
をポインター型に変換すると、算術演算が機能します。
0 + (int*)nullptr;
(int*)nullptr - (int*)nullptr;
NULLマクロを実際にnullptrにすることはできますか?
はい、nullptr
はNULLポインターリテラルであるためです。
C++ 11より前は、C++のすべてのNULLポインターリテラルも整数リテラルであったため、この不正なコード:char c = NULL;
実際に使用されていました。 NULL
がnullptr
として定義されている場合、そのコードは機能しなくなります。
さらに、両方のオペランドが算術またはスコープなしの列挙型を持つか、一方のオペランドが完全に定義されたオブジェクト型へのポインタであり、もう一方が整数またはスコープなしの列挙型でなければなりません。
減算については、次のいずれかが適用されます。
(2.1)両方のオペランドは算術またはスコープなしの列挙型を持っています。または
(2.2)両方のオペランドは、完全に定義された同じオブジェクト型のcv修飾バージョンまたはcv非修飾バージョンへのポインターです。または
(2.3)左のオペランドは完全に定義されたオブジェクト型へのポインタであり、右のオペランドは整数またはスコープなしの列挙型です。
std::nullptr_t
はそれらのどれでもないため、std::nullptr
は、加算演算に参加できません。
すべてのポインター値でさえ参加できるわけではないことに注意してください。たとえば、関数ポインター値とvoidポインター値は、どちらかがNULLポインター値であっても、そうすることはできません。
キーワードnullptr
は、ポインターリテラルを示します。タイプstd::nullptr_t
のprvalue
です。 nullptr
から任意のポインター型およびメンバー型へのポインターのNULLポインター値への暗黙的な変換が存在します。 nullptr
自体はポインター値でもポインターでもありません。したがって、算術演算はnullptr
には適用されません。