Parameter Anordnung egal
-
das wäre einen unendliche Rekursion, intersect sich immer wieder selbst aufruft.
was du suchst, nennt sich "double dispatching":
http://en.wikipedia.org/wiki/Double_dispatch
bzw. "multiple dispatching" / "Multimethoden":
http://www.c-plusplus.net/forum/159235
-
pyhax schrieb:
Würde nicht, wenn sie richtig wären, die überladenen Methoden aufgerufen?

Wenn du die Methode überladen hast, wozu brauchst du dann das Template?
Und ja, es geht mit etwas Templategefrickel, aber das ist viel mehr Arbeit als die Funktion einfach zu überladen. (Und das wiederrum ist viel mehr Arbeit als einfach eine Reihenfolge festzulegen.)
-
cooky451 schrieb:
pyhax schrieb:
Würde nicht, wenn sie richtig wären, die überladenen Methoden aufgerufen?

Wenn du die Methode überladen hast, wozu brauchst du dann das Template?
Und ja, es geht mit etwas Templategefrickel, aber das ist viel mehr Arbeit als die Funktion einfach zu überladen. (Und das wiederrum ist viel mehr Arbeit als einfach eine Reihenfolge festzulegen.)Ich überlade die Funktionen doppelt
(Die Funktionen weil es ja noch intersect(Point, Triangle),intersect(Line, Triangle)... gibt. Oder hat noch jemand eine schlaue Idee ? (Ich mag Boilerplate Code nicht
)
-
Ich versteh das Grundproblem nicht, was ist daran so schlimm eine fixe Schnittstelle vorzugeben und diese zu nutzen. Ich brauche keine Funktionen wo ich die Reihenfolge der Parameter vertauschen kann.
-
okay, also ich habe jetzt mal eine hübsche Lösung mit SFINAE gebastelt:
// nur 2 Beispieltypen: struct point { int x_, y_; }; struct line { int x1_, y1_; int x2_, y2_; }; // also hier kommen deine ganzen Implementationen rein namespace detail { bool intersect_impl(point const & p, line const & l) { int dx1 = l.x2_ - l.x1_; int dy1 = l.y2_ - l.y1_; int dx2 = p.x_ - l.x1_; int dy2 = p.y_ - l.y1_; return (dx1 / dx2) == (dy1 / dy2); } } // Die folgenden Templates werden genutzt, um zwischen intersect_impl(a, b) und intersect_impl(b, a) zu unterscheiden namespace traits { using detail::intersect_impl; typedef char yes; typedef struct { char dummy[2]; } no; no intersect_impl(...); template <typename T1, typename T2> struct impl_exists { static T1 t1; static T2 t2; template <typename T> static yes test(T const &); static no test(no const &); static bool const value = sizeof(test(intersect_impl(t1, t2))) == sizeof(yes); }; template <bool Condition, typename Type> struct enable_if; template <typename Type> struct enable_if<true, Type> { typedef Type type; }; } // und hier die intersect-Funktion, wie man sie aufruft: template <typename T1, typename T2> inline typename traits::enable_if< traits::impl_exists<T1, T2>::value, bool >::type intersect(T1 const & t1, T2 const & t2) { return detail::intersect_impl(t1, t2); } template <typename T1, typename T2> inline typename traits::enable_if< !traits::impl_exists<T1, T2>::value && traits::impl_exists<T2, T1>::value, bool >::type intersect(T1 const & t1, T2 const & t2) { return detail::intersect_impl(t2, t1); } // kleines Beispiel-Programm: #include <iostream> int main() { point p1 = { 1, 1 }, p2 = { 2, 1 }; line l = { 0, 0, 2, 2 }; std::cout << std::boolalpha; std::cout << intersect(p1, l) << "\n"; std::cout << intersect(l, p2) << "\n"; return 0; }Für weitere Typen, die "intersecten" können, brauchst du nur einen neue intersect_impl im detail-Namespace hinzufügen.
Alles weitere übernehmen die Templates automatisch für dich.
-
Cool

-
Oder zur Laufzeit, ganz klassisch. Vielleicht nicht die effizienteste Methode,
aber verständlich.struct shape_t { ... }; struct point_t : public shape_t { ... }; struct triangle_t : public shape_t { ... }; struct line_t : public shape_t { ... } bool intersect(shape_t &first, shape_t &second) { ... };
-
Da ist mir der Strichpunkt verrutscht.

-
Mit C++11 wird es einfacher
template <typename T, typename U> auto intersect(T&& a, U&& b) -> decltype( intersect_impl( std::forward<T>( a ), std::forward<U>( b ) ) ) { return intersect_impl( std::forward<T>( a ), std::forward<U>( b ) ); } template <typename T, typename U> auto intersect(T&& a, U&& b) -> decltype( intersect_impl( std::forward<U>( b ), std::forward<T>( a ) ) ) { return intersect_impl( std::forward<U>( b ), std::forward<T>( a ) ); }
-
camper schrieb:
Mit C++11 wird es einfacher
template <typename T, typename U> auto intersect(T&& a, U&& b) -> decltype( intersect_impl( std::forward<T>( a ), std::forward<U>( b ) ) ) { return intersect_impl( std::forward<T>( a ), std::forward<U>( b ) ); } template <typename T, typename U> auto intersect(T&& a, U&& b) -> decltype( intersect_impl( std::forward<U>( b ), std::forward<T>( a ) ) ) { return intersect_impl( std::forward<U>( b ), std::forward<T>( a ) ); }
Das nehme ichHat das auch was mit SFINAE zu tun? Oder wie funktioniert das?
-
Du mußt eh eine Reihenfolge festlegen, um nicht wahnsinnig zu werden.
Vielleicht einfach lexikographisch.Und oh, Schreck, welche Unmengen an Boilerplate…
Damit will ich sagen, es ist wirklich wenig.bool intersect_impl(point const & p, line const & l) { int dx1 = l.x2_ - l.x1_; int dy1 = l.y2_ - l.y1_; int dx2 = p.x_ - l.x1_; int dy2 = p.y_ - l.y1_; return (dx1 / dx2) == (dy1 / dy2); //Und die anderen intersects werden schlimmer und größer } //Und immer eine umgedrehte Fassung anbieten bool intersect(line const & l, point const & p) { return intersect(p,l); }
-
pyhax, die C++11 Variante nutzt auch SFINAE, setzt aber das neue decltype-Schlüsselwort ein,
das eben noch nicht alle Compiler unterstützen
(mit einigermaßen aktuellem GCC oder MSVC ab Version 10 bist du aver gut dabei ;-))