2013-04-19 8 views
5

Ich verstehe, dass bei der generischen Programmierung Algorithmen von Containern entkoppelt sind. Es würde also keinen Sinn machen, einen generischen Algorithmus als Instanzmethode zu implementieren (derselbe Algorithmus sollte an mehreren konkreten Klassen arbeiten; wir wollen nicht, dass sie alle von einem ABC erben, da dies die Anzahl der Klassen exponentiell erhöhen würde).Warum ist Boost Graph Library `source()` eine globale Funktion?

Aber im Fall von source() Funktion in der Boost Graph Library, verstehe ich nicht, warum es eine globale Funktion und keine Instanzmethode einer Graphenklasse ist.

Soweit ich durch das Lesen der BGL source code sagen konnte, muss source(e, g) die Implementierungsdetails der Graph und Randobjekte an sie übergeben kennen; es ist nicht genug, nur ihre Schnittstellen zu kennen.

Also source() ist kein generischer Algorithmus. Mit anderen Worten, es muss die konkrete Klasse der Graphinstanz kennen. Warum also nicht in dieselbe Klasse wie eine Instanzmethode? Wäre es nicht viel sauberer/weniger verwirrend als eine globale Funktion zu erstellen, die an jede Klasse angepasst werden muss?

UPDATE

Der entsprechende Quellcode:

// dwa 09/25/00 - needed to be more explicit so reverse_graph would work. 
    template <class Directed, class Vertex, 
     class OutEdgeListS, 
     class VertexListS, 
     class DirectedS, 
     class VertexProperty, 
     class EdgeProperty, 
     class GraphProperty, class EdgeListS> 
    inline Vertex 
    source(const detail::edge_base<Directed,Vertex>& e, 
     const adjacency_list<OutEdgeListS, VertexListS, DirectedS, 
       VertexProperty, EdgeProperty, GraphProperty, EdgeListS>&) 
    { 
    return e.m_source; 
    } 


namespace boost { 

    namespace detail { 

    template <typename Directed, typename Vertex> 
    struct edge_base 
    { 
     inline edge_base() {} 
     inline edge_base(Vertex s, Vertex d) 
     : m_source(s), m_target(d) { } 
     Vertex m_source; 
     Vertex m_target; 
    }; 
    } 
} 
+0

Kein Grund Quelle (a, b) kann nicht basierend auf den Typen seiner Parameter spezialisiert werden. Nicht alles muss eine Mitgliedsfunktion sein. Einige freie Funktionen können als Teil der Schnittstelle einer Klasse angesehen werden. Zusätzlich kann es nützlich sein, source() als Shim zu verwenden. Ohne den Code zu lesen und zu verstehen (was nicht innerhalb von 2 Klicks auf Ihre Links möglich ist), konnte ich Ihnen das nicht wirklich sagen, da ich die Graphenbibliothek nicht verwende, aber sie könnten Dinge sein, die zu berücksichtigen sind. Alternativ senden Sie die BGL-Entwickler direkt und fragen nach ihrer Designentscheidung. Ich nehme an es gibt einen guten Grund dafür – Pete

+0

Gibt es einen Grund, warum es dich stört? – Pete

+2

http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197 –

Antwort

6

Der source(e, g) ist kein generischer Algorithmus. Sein Teil der Schnittstelle, normalerweise ein Konzept in C++ genannt. Der Grund dafür, eine Nichtmitgliedsfunktion zu sein, ist so, dass sie nicht-intrusiv implementiert werden kann.

Sagen Sie zum Beispiel, Sie wollten std::multimap, um das IncidenceGraph Konzept zu implementieren. Wenn die Graphenbibliothek source() als Member-Funktion benötigt, wäre das kein Glück, da std::multimap keinen solchen enthält.

+0

Ich bin mir sicher, dass das der Grund ist. Aber warum ist es schlecht, von "multimap" zu erben und "source" als Elementfunktion hinzuzufügen? – max

+0

@max Es ist nicht schlecht, es löst nur nicht das Problem, 'std :: multimap' ein' IncidenceGraph' zu machen –

+0

Wenn ich Sie richtig verstehe, sprechen Sie über die folgende Situation. Angenommen, ich bekomme ein Objekt 'data', das eine Instanz von' std :: multimap' ist. Ich möchte "Daten" als Graphen interpretieren, indem ich Schlüsselwerte als Graphscheitelpunkte behandle und die zugeordneten Werte als Adjazenzlisten. Ich kann sehen, warum der Ansatz der Nichtmitgliedfunktion hier gut funktioniert. Aber was passiert, wenn ich "Daten" mit zwei verschiedenen Interpretationen als Graphen behandeln will? Ich muss dann zwei Sätze von Nicht-Member-Funktionen schreiben. Wie würden sie vermeiden, dass sie miteinander kollidieren? Benötigt BGL nicht, dass sie alle im selben Namespace sind? – max

3

In C++ sollte man nicht-Mitglied nicht-friend-Funktionen bevorzugen, wo es möglich ist, dies zu tun. Wenn source in Bezug auf die öffentlichen Mitglieder der Klassen implementiert werden kann, auf die es angewendet werden soll, sollte es außerhalb der Klasse liegen.

Dies hat nichts mit generischen Algorithmen zu tun; Es geht ausschließlich darum, die Menge an Code zu reduzieren, die Zugriff auf den internen Status der privaten Mitglieder der Klasse hat oder diesen beschädigen kann.

+0

Danke. Es ist in der Tat eine Nicht-Freund-Funktion, weil das Objekt, auf das es zugreift, nur öffentliche Mitglieder hat (tatsächlich ist es eine Struktur).Ich glaube jedoch nicht, dass ich verstehe, warum diese Mitglieder veröffentlicht werden. Siehe [mein früherer Kommentar] (http://stackoverflow.com/questions/16114616/why-is-boost-graph-librarys-source-a-global-function#comment23015326_16114616). – max

+0

@max es hängt davon ab, ob die Klasse/Struktur die Verletzung einer Invariante verhindern soll. In diesem Fall haben die zwei Vertices, die die Struktur enthält, keine echte Invariante, die beibehalten werden muss (d. H. Sie ist legal, wenn sie derselbe Vertex sind). Wenn es keine Invariante gibt, warum müssen die Mitglieder privat sein? Konsistenz? Alternativ könnte es sein, dass die BGL-Entwickler nicht daran interessiert sind, den gesamten Klebecode zu schreiben. – Pete

Verwandte Themen