2016-04-25 4 views
8

Als Teil des Hashing muss ich einen Funktionszeiger in eine Zeichenfolgendarstellung konvertieren. Mit global/statischen Funktionen ist es trivial:Wie erhalten Sie eine String-Repräsentation für die Member-Funktion?

string s1{ to_string(reinterpret_cast<uintptr_t>(&global)) }; 

Und von here:

2) Jeder Zeiger kann auf jeden integralen Typ, der groß genug, um umgewandelt werden halten den Wert des Zeigers (zB std::uintptr_t

)

Aber ich habe ein Problem mit Member-Funktionen:

cout << &MyStruct::member; 

Ausgänge 1 obwohl im Debugger kann ich die Adresse sehen.

string s{ to_string(reinterpret_cast<uintptr_t>(&MyStruct::member)) }; 

Gibt einen Kompilierungsfehler cannot convert. Es scheint also, dass kein Zeiger konvertiert werden kann.

Was kann ich noch tun, um eine String-Darstellung zu erhalten?

+0

'1' könnte der richtige Wert sein. Mitgliedsfunktionszeiger sind schließlich relativ. Das bedeutet auch, dass Sie möglicherweise auf viele Kollisionen stoßen, wenn Sie keine zusätzlichen Informationen wie den Hash der Typid des Typs selbst hinzufügen. Und wenn Sie sagen, * dass kein Zeiger konvertiert werden kann *, beachten Sie, dass die Zeiger der Mitgliedsfunktion * keine * Zeiger sind; sie sind genau * Mitgliedsfunktionszeiger *. –

+1

"So scheint es, dass kein Zeiger konvertiert werden kann." Ein Zeiger ist nicht dasselbe wie ein Zeiger auf Member, Zeiger können in einen ganzzahligen Typ konvertiert werden, Pointer auf Member können nicht. – user657267

+5

Es gibt keinen 'Operator <<' für Zeiger zu Element. '& MyStruct :: member' ist ein Nicht-Null-Pointer-to-Member. Jeder Zeiger kann implizit in 'bool' konvertiert werden. Non-NULL-Zeiger werden in 'true' konvertiert, die standardmäßig als '1' ausgegeben werden. – molbdnilo

Antwort

4
cout << &MyStruct::member; 

Ausgänge 1 obwohl in Debugger ich die Adresse sehen können.

Es gibt keine Überlastung für ostream::operator<<(decltype(&MyStruct::member)). Der Elementfunktionszeiger ist jedoch implizit in bool konvertierbar, und daher gibt es eine Überladung, die am besten zur Überladungsauflösung passt. Der konvertierte Wert ist true, wenn der Zeiger nicht null ist. true wird als 1 ausgegeben.


string s{ to_string(reinterpret_cast<uintptr_t>(&MyStruct::member)) }; 

Gibt einen Fehler bei der Kompilierung nicht konvertieren kann. Es scheint also, dass kein Zeiger konvertiert werden kann.

Vielleicht verwechselbar, in standardese Zeiger ist nicht ein Oberbegriff für Objektzeiger, Zeiger-to-Mitglieder, Zeiger zu Funktionen und die Zeiger-to-Mitgliedsfunktionen. Zeiger bedeuten speziell nur Datenzeiger.

Die zitierte Regel gilt also nicht für Zeiger-zu-Stab-Funktionen. Es gilt nur für (Objekt-) Zeiger.


Was kann ich sonst noch tun, um eine String-Darstellung zu bekommen?

Sie können einen Puffer von unsigned char, groß genug, um den Zeigepfeil zu repräsentieren, und std::memcpy verwenden. Dann drucken Sie es in dem Format Ihrer Wahl. Ich empfehle hexadezimal.

Wie Martin Bonner darauf hinweist, kann der pointer-to-member Padding enthalten. In diesem Fall können zwei Werte, die auf dasselbe Element verweisen, möglicherweise einen anderen Wert im Puffer haben.Daher ist der gedruckte Wert nicht von großem Nutzen, da zwei Werte nicht vergleichbar sind, ohne zu wissen, welche Bits (wenn überhaupt) aufgefüllt sind - was die Implementierung ist.


Leider muß ich eine robuste Lösung, weil diese Polsterung ich nicht verwenden kann.

Keine tragbare robuste Lösung vorhanden ist.

Wie Jonathan Wakely darauf hinweist, gibt es keine Padding-Funktion im Itanium ABI. Wenn der Compiler dies verwendet, funktioniert die vorgeschlagene memcpy-Methode.

+0

Es besteht das Risiko, dass einige der Daten eines * pointer-to-member * Padding Space ignoriert werden. In diesem Fall können verschiedene Variablen, die einen Zeiger auf dasselbe Element enthalten, unterschiedliche Füllwerte haben - und das Ausgeben in hexadezimal würde (falsch) einen anderen Hash ergeben. Ich bin mir nicht sicher, ob das ein Problem ist, das (im Allgemeinen) ohne Compiler-Unterstützung gelöst werden kann. (In der Praxis wird Ihr Vorschlag wahrscheinlich funktionieren.) –

+0

@MartinBonner guter Punkt. Ich habe nicht darüber nachgedacht, wofür Nikitablack die String-Repräsentation verwenden könnte. – user2079303

+0

Danke. Leider brauche ich eine robuste Lösung deswegen kann ich wegen dieser Polsterung nicht verwenden. Außerdem weiß ich nicht, wie ich es kopieren soll. 'memcpy' akzeptiert' void * 'als Quelle, aber * pointer-to-member * kann nicht in es konvertiert werden. – nikitablack

Verwandte Themen