Pregunta

I understand that in generic programming, algorithms are decoupled from containers. So it would make no sense to implement a generic algorithm as an instance method (the same algorithm should work on multiple concrete classes; we don't want to make them all inherit from one ABC since it would exponentially increase the number of classes).

But in the case of source() function in the Boost Graph Library, I don't understand why it is a global function and not an instance method of a graph class.

As far as I could tell by reading the BGL source code, source(e, g) needs to know the implementation details of the graph and edge objects passed to it; it's not enough to know just their interfaces.

So source() is not a generic algorithm. In other words, it needs to know the concrete class of the graph instance. Then why not put it in that same class as an instance method? Wouldn't it be a lot cleaner / less confusing than making a global function that needs to be customized to each class it's called upon?

UPDATE

The relevant source code:

  // 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;
    };
  }
}
¿Fue útil?

Solución

The source(e, g) is not a generic algorithm. Its part of the interface, usually called a concept in C++. The reason for being a non-member function is so that it can be implemented non-intrusively.

Say, for instance, you wanted std::multimap to implement the IncidenceGraph concept. If the graph library required source() to be a member function you would be out of luck, since std::multimap doesn't provide one.

Otros consejos

In C++, one should prefer non-member non-friend functions where it is possible to do so. If source can be implemented in terms of the public members of the classes it is designed to operate upon, it should be outside of the class.

This has nothing to do with making things generic algorithms; it is entirely about reducing the amount of code that has access to / can corrupt internal state of the private members of the class.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top