web-dev-qa-db-ja.com

NULLマクロを実際にnullptrにすることはできますか?

標準N4713(7.11/1)のドラフトによると:

NULLポインター定数は、値がゼロの整数リテラル(5.13.2)またはstd::nullptr_t型のprvalueです。

および21.2.3/2:

マクロNULLは、実装定義のNULLポインター定数です。

NULLnullptrとして定義できます。 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として定義できないものはありますか?

41

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になります。

47
Baum mit Augen

nullptrはNULLポインターリテラルであり、nullptrをポインター型に変換した結果はNULLポインター値ですが、nullptr自体はポインター型ではありませんが、タイプstd::nullptr_tnullptrをポインター型に変換すると、算術演算が機能します。

0 + (int*)nullptr; 
(int*)nullptr - (int*)nullptr;

NULLマクロを実際にnullptrにすることはできますか?

はい、nullptrはNULLポインターリテラルであるためです。

C++ 11より前は、C++のすべてのNULLポインターリテラルも整数リテラルであったため、この不正なコード:char c = NULL;実際に使用されていました。 NULLnullptrとして定義されている場合、そのコードは機能しなくなります。

7
eerorika

さらに、両方のオペランドが算術またはスコープなしの列挙型を持つか、一方のオペランドが完全に定義されたオブジェクト型へのポインタであり、もう一方が整数またはスコープなしの列挙型でなければなりません。

減算については、次のいずれかが適用されます。
(2.1)両方のオペランドは算術またはスコープなしの列挙型を持っています。または
(2.2)両方のオペランドは、完全に定義された同じオブジェクト型のcv修飾バージョンまたはcv非修飾バージョンへのポインターです。または
(2.3)左のオペランドは完全に定義されたオブジェクト型へのポインタであり、右のオペランドは整数またはスコープなしの列挙型です。

std::nullptr_tはそれらのどれでもないため、std::nullptrは、加算演算に参加できません。

すべてのポインター値でさえ参加できるわけではないことに注意してください。たとえば、関数ポインター値とvoidポインター値は、どちらかがNULLポインター値であっても、そうすることはできません。

6
n.m.

キーワードnullptrは、ポインターリテラルを示します。タイプstd::nullptr_tprvalueです。 nullptrから任意のポインター型およびメンバー型へのポインターのNULLポインター値への暗黙的な変換が存在します。 nullptr自体はポインター値でもポインターでもありません。したがって、算術演算はnullptrには適用されません。

5
S.M.