Ich bin gespannt, wie nullptr
das geht. Die Standards N4659 und N4849 sagen:
- es muss Typ haben
std::nullptr_t
; - Sie können seine Adresse nicht nehmen;
- Es kann direkt in einen Zeiger und einen Zeiger auf ein Mitglied konvertiert werden.
sizeof(std::nullptr_t) == sizeof(void*)
;;- seine Umwandlung in
bool
istfalse
; - sein Wert kann identisch
(void*)0
, aber nicht rückwärts in einen ganzzahligen Typ umgewandelt werden ;
Es ist also im Grunde eine Konstante mit der gleichen Bedeutung wie (void*)0
, aber es hat einen anderen Typ. Ich habe die Implementierung std::nullptr_t
auf meinem Gerät gefunden und es ist wie folgt.
#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
Der erste Teil interessiert mich allerdings mehr. Es scheint die Punkte 1-5 zu erfüllen, aber ich habe keine Ahnung, warum es eine Unterklasse __nat und alles, was damit zu tun hat, hat. Ich würde auch gerne wissen, warum es bei integralen Konvertierungen fehlschlägt.
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){};
};
c++
c++17
nullptr
null-pointer
Fullfungo
quelle
quelle
nullptr_t
ist ein grundlegender Typ. Wie wirdint
umgesetzt?#ifdef _LIBCPP_HAS_NO_NULLPTR
. Dies scheint eine bestmögliche Problemumgehung zu sein, wenn der Compiler keine Bereitstellung bietetnullptr
.nullptr_t
ein grundlegender Typ ist. Die Implementierung als Klassentyp führt nicht zu einer konformen Implementierung. Siehe Chris 'Kommentar.is_class
undis_null_pointer
kann nicht beide für den gleichen Typ wahr sein. Nur eine der Funktionen der primären Typkategorie kann für einen bestimmten Typ true zurückgeben.Antworten:
Es funktioniert auf einfachste Weise: per Fiat . Es funktioniert, weil der C ++ - Standard sagt, dass es funktioniert, und es funktioniert so, wie es funktioniert, weil der C ++ - Standard sagt, dass Implementierungen dafür sorgen müssen, dass es auf diese Weise funktioniert .
Es ist wichtig zu erkennen, dass es unmöglich ist ,
std::nullptr_t
mit den Regeln der C ++ - Sprache zu implementieren . Die Konvertierung von einer Nullzeigerkonstante vom Typstd::nullptr_t
in einen Zeiger ist keine benutzerdefinierte Konvertierung. Das bedeutet, dass Sie von einer Nullzeigerkonstante zu einem Zeiger und dann durch eine benutzerdefinierte Konvertierung zu einem anderen Typ in einer einzigen impliziten Konvertierungssequenz wechseln können.Dies ist nicht möglich, wenn Sie
nullptr_t
als Klasse implementieren . Konvertierungsoperatoren stellen benutzerdefinierte Konvertierungen dar, und die impliziten Konvertierungssequenzregeln von C ++ erlauben nicht mehr als eine benutzerdefinierte Konvertierung in einer solchen Sequenz.Der Code, den Sie gepostet haben, ist also eine nette Annäherung an
std::nullptr_t
, aber es ist nichts weiter als das. Es ist keine legitime Implementierung dieses Typs. Dies war wahrscheinlich eine ältere Version des Compilers (aus Gründen der Abwärtskompatibilität), bevor der Compiler die richtige Unterstützung für bereitstelltestd::nullptr_t
. Sie können dies durch die Tatsache , dass es#define
snullptr
, während C ++ 11 sagt , dassnullptr
ist ein Schlüsselwort , kein Makro.C ++ kann nicht implementiert werden
std::nullptr_t
, genauso wie C ++ nicht implementieren kannint
odervoid*
. Nur die Implementierung kann diese Dinge implementieren. Dies macht es zu einem "fundamentalen Typ"; Es ist ein Teil der Sprache .Es gibt keine implizite Konvertierung von einer Nullzeigerkonstante in integrale Typen. Es gibt eine Konvertierung von
0
in einen ganzzahligen Typ, aber das liegt daran, dass es sich um das ganzzahlige Literal Null handelt, das ... eine Ganzzahl ist.nullptr_t
kann gegossen (über in einen Integer - Typreinterpret_cast
), aber es kann nur implizit auf Zeiger und konvertiert werdenbool
.quelle
std::nullptr_t
. Genauso wie Sie keinen Typ schreiben können, der genau dem Verhalten entspricht, das von erforderlich istint
. Sie können nah dran sein, aber es wird immer noch signifikante Unterschiede geben. Und ich spreche nicht von solchen Merkmaldetektorenis_class
, die zeigen, dass Ihr Typ benutzerdefiniert ist. Es gibt Dinge über das erforderliche Verhalten grundlegender Typen, die Sie mit den Regeln der Sprache einfach nicht kopieren können.nullptr_t
", sprechen Sie zu weit. Und zu sagen "nur die Implementierung kann es implementieren" verwirrt nur die Sache. Was Sie damit meinen, ist, dassnullptr_t
dies nicht in der C ++ - Bibliothek implementiert werden kann, da es Teil der Basissprache ist.std::nullptr_t
dazu erforderlich ist. Genau wie C ++ kann die Sprache keinen Typ implementieren, der alles tut, wasint
erforderlich ist.