10

I want to replace the BGL iteration over vertexes or edges with pure C++11 equivalent. The BGL code (from: http://www.boost.org/doc/libs/1_52_0/libs/graph/doc/quick_tour.html) is:

typename boost::graph_traits<Graph>::out_edge_iterator out_i, out_end;
typename boost::graph_traits<Graph>::edge_descriptor e;
for (std::tie(out_i, out_end) = out_edges(v, g);
     out_i != out_end; ++out_i)
{
  e = *out_i;
  Vertex src = source(e, g), targ = target(e, g);
  std::cout << "(" << name[get(vertex_id, src)]
            << "," << name[get(vertex_id, targ)] << ") ";
}

I tried several suggestions from here: Replace BOOST_FOREACH with "pure" C++11 alternative? but without luck.

I want to be able to write something like:

for (auto &e : out_edges(v, g))
{ ... }

or something like:

for (std::tie(auto out_i, auto out_end) = out_edges(v, g);
     out_i != out_end; ++out_i)
{...}

Is it possible?

Community
  • 1
  • 1
Wojciech Danilo
  • 11,573
  • 17
  • 66
  • 132

2 Answers2

9

A simple wrapper over out_edges should suffice:

#include <boost/range/iterator_range.hpp>
#include <type_traits>

template<class T> using Invoke = typename T::type
template<class T> using RemoveRef = Invoke<std::remove_reference<T>>;
template<class G> using OutEdgeIterator = typename boost::graph_traits<G>::out_edge_iterator;

template<class V, class G>
auto out_edges_range(V&& v, G&& g)
  -> boost::iterator_range<OutEdgeIterator<RemoveRef<G>>>
{
  auto edge_pair = out_edges(std::forward<V>(v), std::forward<G>(g));
  return boost::make_iterator_range(edge_pair.first, edge_pair.second);
}

Or even simpler, a function that turns a std::pair into a valid range:

template<class It>
boost::iterator_range<It> pair_range(std::pair<It, It> const& p){
  return boost::make_iterator_range(p.first, p.second);
}

and then

for(auto e : pair_range(out_edges(v, g))){
  // ...
}
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • Thank you, but the code provided by you does not even compile :( Please take a look at the source code (with yours code included): http://pastebin.com/Nx7WeMhU – Wojciech Danilo Nov 19 '12 at 12:40
  • here they are: http://pastebin.com/LDLRYwNG (Additional I added ';' to line 20, because there is missing semicolon syntax error without it) – Wojciech Danilo Nov 19 '12 at 12:45
  • @danilo2: The robot fixed my answer just now, it was missing a simply `` in the `RemoveReference` using-alias. – Xeo Nov 19 '12 at 12:48
  • Thank you, now it compiles, but when using it like that: for (auto &e : out_edges_range(v, g)){} I got another error: http://pastebin.com/QS5qJQWM – Wojciech Danilo Nov 19 '12 at 12:58
  • @danilo2: I honestly have *no* idea what's causing that error. Maybe you're better off with my second solution, I hope that one atleast works. – Xeo Nov 19 '12 at 13:14
  • It does not work either :( Here is the error from gcc: http://pastebin.com/VLEZ1MYp and from clang (more informative to me): http://pastebin.com/yKxFDJKL (and the source: http://pastebin.com/TbKQidmk) – Wojciech Danilo Nov 19 '12 at 13:48
  • 1
    @danilo2: I just noticed your `e` in the question is also a simple value - just do `for(auto e : out_edges_range(v, g))` then. The problem is that `out_edge_iterator`s return by-value when dereferencing them, they're so-called *proxy-iterators*. – Xeo Nov 19 '12 at 14:09
  • What is very interesting it started to work after I enabled optimalization. With -O0 it gives me some errors. It is true for BGL (see here: http://www.boost.org/doc/libs/1_52_0/libs/graph/doc/index.html). Could somebody explain to me why optimalization influences the compilation in such way? – Wojciech Danilo Nov 19 '12 at 16:04
3

Boost.Graph also provides convenience macros similar to BOOST_FOREACH but designed specifically for Graph iterations.

Iteration over all vertices/edges of a given graph is provided by macros BGL_FORALL_VERTICES/ BGL_FORALL_EDGES and their template counterparts BGL_FORALL_VERTICES_T/BGL_FORALL_EDGES_T.

Iteration over in- or out- edges of a given vertex is provided by macros BGL_FORALL_OUTEDGES or BGL_FORALL_INEDGES. (Add _T for their template versions). For adjacency vertices use BGL_FORALL_ADJ.

Example:

#include <boost/graph/iteration_macros.hpp>

typedef ... Graph;
Graph g;
BGL_FORALL_VERTICES(v, g, Graph)  //v is declared here and 
{                                   //is of type Graph::vertex_descriptor
     BGL_FORALL_OUTEDGES(v, e, g, Graph)  //e is declared as Graph::edge_descriptor
     {

     }
}

The macros work both in C++03 and C++11.

Neel Basu
  • 12,638
  • 12
  • 82
  • 146
Michael Simbirsky
  • 3,045
  • 1
  • 12
  • 24