Frage Wie drucke ich die Adresse eines Methodenzeigers in C ++?


Beispielsweise:

struct A { void m() { } };

void stream_print() {
  void(A::*p)(void) = &A::m;
  std::cerr << p << std::endl;
}

void printf_print() {
  void(A::*p)(void) = &A::m;
  fprintf(stderr, "%p", p);
}

Die Funktion stream_print () gibt immer "1" aus, was offensichtlich nicht das ist, was ich möchte. Printf_print wird nicht kompiliert, da p nicht in void * umgewandelt werden kann.

Was ich brauche, ist ein eindeutiger Bezeichner für einen Methodenzeiger, den ich in einem Container speichern kann. Ich weiß, das hört sich nach einer schlechten Idee an, aber ich entwickle ein kleines Spielzeug für Unit-Tests, das davon profitieren kann. Ich mache mir keine Sorgen über Überladungen der Methode, ich weiß, wie man den Zeiger auf eine bestimmte Überladung bringt.

Ich verwende g ++ 4.4.3 mit C ++ 0x aktiviert.

Lass es mich wissen, wenn du irgendwelche Zweifel hast.


7
2018-03-20 06:45


Ursprung


Antworten:


Mitgliedsfunktionszeiger ist im Allgemeinen ein Objekt mit nicht-trivialer interner Struktur. Aus diesem Grund können Sie es nicht mit Werkzeugen drucken, die zum Drucken primitiver Typen vorgesehen sind. Wirf den Zeiger auf void * ist kein praktikabler Ansatz, da die Größe des Elementzeigers im Allgemeinen größer ist als sizeof(void *). Erzwingt es gewaltsam zu void * wird in jedem Fall einen Teil der Zeigerdarstellung verwerfen und somit die Eindeutigkeit nicht mehr garantieren.

Wenn das, was Sie suchen, eine eindeutige Zeichenfolge ist, die vom Zeiger generiert wird, können Sie den Zeiger als Zeichenfeld neu interpretieren und die Zeichenfolgendarstellung von Zeichenwerten im Bezeichner verwenden. Etwas wie

void (A::*p)(void) = &A::m;

for (size_t i = 0; i < sizeof p; ++i)
  printf("%d ", reinterpret_cast<char *>(&p)[i]);

printf("\n");

9
2018-03-20 07:41



Obwohl ich mir nicht 100% ig sicher bin, verstehe ich die Frage richtig, wenn man etwas mappt Von einem Mitgliedszeiger zu einer eindeutigen ID wird der folgende Code benötigt den Zweck erfüllen:

struct A {
  void f() {}
  void g( int ) {}
};

template< class T, T >
char* get_unique_id() {
  static char dummy;
  return &dummy;
}

int main() {
  set< char* >  s;
  s.insert( get_unique_id< decltype( &A::f ), &A::f >() );
  s.insert( get_unique_id< decltype( &A::g ), &A::g >() );
  s.insert( get_unique_id< decltype( &A::f ), &A::f >() );
  s.insert( get_unique_id< decltype( &A::g ), &A::g >() );
  cout<< s.size() <<endl; // prints 2
}

Der Ruf von get_unique_id ist ein bisschen lang, obwohl ...
Vermutlich könnte ein Makro helfen, es einfacher zu machen.

Hoffe das hilft


4
2018-03-20 10:02



Wenn es nur mit GCC funktionieren soll, könntest du es verwenden Dies Erweiterung zum Extrahieren eines Funktionszeigers von einem Zeiger zur Elementfunktion.

Hier ist ein Beispiel:

#include <iostream>
#include <stdio.h>

struct A { void m() { } };

typedef void (*mptr)(A*);

int main()
{
    mptr p = (mptr)(&A::m);
    std::cerr << (void*)p << std::endl;
    fprintf(stderr, "%p\n", p);
}

Kompilieren mit -Wno-pmf-conversions um die Warnung zu unterdrücken.


1
2018-03-20 11:55



Es gibt keinen tragbaren Weg, dies zu tun. Aber hast du es versucht? reinterpret_cast<void*>(p)?

Ich vermute stream_print benutzt std::operator<<(std::ostream&, bool), da dies die einzige gültige Konvertierung für einen Zeiger-zu-Element-Typ ist. Das würde erklären, warum du gehst 1.

Das hätte ich nicht erwartet printf_print funktionieren, auch wenn ein Compiler die Übergabe einer Pointer-zu-Member-Funktion erlaubt hat .... Es gibt keine Garantie sizeof(p) == sizeof(void*)Dies ist oft ein praktisches Minimum, um "erwartete" Nicht-Standard-Ergebnisse zu erhalten va_arg.


0
2018-03-20 07:01