fehlende Methode wird erst zur Laufzeit bemerkt?
-
Hi,
ich wollte die Vergleichsoperatoren für boost.any überladen, sodass ein paar bestimmte Typen verglichen werden, während andere Typen eine Exception schmeißen. Warum ich das mache, oder warum ich das mit Makro mache ist hier irrelevant, es funktioniert auch alles gut, nur etwas ist merkwürdig: Das folgende Beispiel kompiliert und der == Operator funktioniert auch problemlos, nur warum kompiliert es eigentlich? Die anderen Vergleichsoperatoren sind für A gar nicht überladen und wenn ich es aufrufe kriege ich eine Segmentation Fault(Laut GDBs Stacktrace ruft sich der == Operator immer und immer wieder selbst auf?).
Wieso kriege ich keine Fehlermeldung vom Compiler sondern eine Segfault?class A { public: A(int a) : m_a(a){} bool operator==(A const& that){return that.m_a == m_a;} private: int m_a; }; #define COMPARE_TYPE(TYPE1,TYPE2,COMPARE) if(a.type().name() == typeid(TYPE1).name() && b.type().name() == typeid(TYPE2).name()) \ return any_cast<TYPE1>(a) COMPARE any_cast<TYPE2>(b); \ else #define DYNAMIC_COMPARISON(COMPARE) \ bool operator COMPARE(any const& a, any const& b) \ { \ COMPARE_TYPE(int, int,COMPARE) \ COMPARE_TYPE(A,A,COMPARE) \ cout << "Fehler" << endl; \ } DYNAMIC_COMPARISON(==); DYNAMIC_COMPARISON(!=); DYNAMIC_COMPARISON(<=); DYNAMIC_COMPARISON(<); DYNAMIC_COMPARISON(>); DYNAMIC_COMPARISON(>=); int main() { any a(A(2)); any b(A(2)); try { cout << (a == b) << endl; } catch(...) { cout << "uh exception" << endl; } }
-
Also es hat einen Fehler im Code, der womöglich zu undefiniertem Verhalten führen könnte, da nicht alle Kontrollwege im Vergleichsoperator einen Wert zurückgeben. Der Fehler liegt bei diesem Vergleich:
a.type().name() == typeid(TYPE1).name() && b.type().name() == typeid(TYPE2).name()Im Standard ist nicht definiert, dass die Namen von Typen gleich sind, sondern der Vergleich der
type_infoObjekte muss gleich sein. Also korrekt wäre das hier:a.type() == typeid(TYPE1) && b.type() == typeid(TYPE2)Wenn ich diesen Fehler korrigiere, dann funktioniert dein Code bei mir einwandfrei (VC2008).
Grüssli
-
geändert, ändert aber nichts am Verhalten.
Der Code funktioniert ja auch, nur er sollte meiner Auffassung nach nicht kompilieren, weil <, <=, !=, > und >= für A nicht überladen sind und wenn ich sie aufrufe krieg ich auch eine Segfault.
Oder meinst du mit einwandfrei funktionieren, dass er nicht funktioniert?
-
Also dein präsentierter Code funktioniert bei mir dann, also den
operator ==und es gibt auch ein gültiges Resultat zurück.
Das auch einoperator >=funktioniert, obwohlAkeinen definiert hat und es dann zu einer Rekursion kommt, liegt doch auf der Hand? Wieso hat wohl Boost.Any keine Vergleichsoperatoren definiert? Der Konstruktor von Boost.Any ist nicht explizit sondern halt eben implizit. Es gibt keinenoperator >=fürA, daher wird weitergesucht. Da findet der Kompiler wieder>=fürboost::anyund durch einen impliziten Cast, kann dieser Operator auch verwendet werden. Alles in Butter, denkt sich da der Kompiler
Grüssli
-
ahh, das macht Sinn.
Aber das heißt dann doch auch, dass wenn ich die Vergleichsoperatoren für boost.any implementiere ich immer einen solchen Fehler bekomme, wenn ich Vergleichsoperatoren für egal welchen Typ aufrufe, der keine Vergleichsoperatoren implementiert hat, oder?
Das ist natürlich unerwünscht, kann ich da irgendwas dran ändern? (vermutlich nicht, also redesign..)
-
JustAnotherNoob schrieb:
Aber das heißt dann doch auch, dass wenn ich die Vergleichsoperatoren für boost.any implementiere ich immer einen solchen Fehler bekomme, wenn ich Vergleichsoperatoren für egal welchen Typ aufrufe, der keine Vergleichsoperatoren implementiert hat, oder?
Ehm, also wenn ich deine Frage richtig verstanden habe, was ich eigentlich glaube, aber halt nicht ganz sicher bin, da es wohl ein fehlendes Komma hat, was zwar nicht weiter schlimm ist, durchaus aber beim Verständnis stören kann, dann denke ich, bzw. bin eigentlich davon überzeugt, dass die Antwort, auf deine oben gestellte Frage, JA lautet.
*SCNR*

JustAnotherNoob schrieb:
Das ist natürlich unerwünscht, kann ich da irgendwas dran ändern? (vermutlich nicht, also redesign..)
Boost.Any umschreiben, bzw. den Konstruktor
explicitmachen.
Ansonsten fällt mir nicht sehr viel sinnvolles ein. Du könntest natürlich eine Comparison Klasse machen, welche im Konstruktor die beiden Vergleichsobjekte erwartet. Den Konstruktor von dieser Klasse machst du explicit und gibst der Klasse Methoden für die Vergleiche. Ich gebe am besten einen kurzen Quellcode an, aber ich empfinde das nicht als saubere Lösung
class Comparison { private: boost::any const& m_lhs; boost::any const& m_rhs; public: explicit Comparison(boost::any const& lhs, boost::any const& rhs) : m_lhs(lhs) , m_rhs(rhs) { } // Wobei eigentlich das explicit durch die Trennung von den Operatoren, // gar nicht mehr nötig wäre ... public: bool is_equal() { /* ... */ } bool is_equal_or_greater() { /* ... */ } // ... usw };... ich finde es sogar äusserst hässlich

Grüssli