adjacency_list_traits<EdgeList, VertexList, Directed>
Pre-declares the descriptor types of an adjacency_list before the
adjacency_list itself is declared. Exists to break a chicken-and-egg
compile error users hit exactly once — and then want to know about forever.
Defined in: <boost/graph/adjacency_list.hpp>
Why this class exists
Suppose you want an interior edge property whose value is a
vertex_descriptor — say, storing a predecessor directly on each
edge instead of maintaining an external predecessor map. The naive spelling
// This does NOT compile:
using Graph = adjacency_list<
vecS, vecS, directedS,
no_property,
property<edge_name_t,
graph_traits<Graph>::vertex_descriptor>>; // Graph not yet defined
fails because graph_traits<Graph> cannot be instantiated until Graph
is a complete type, but Graph cannot be completed until its property
type is known. adjacency_list_traits exposes the descriptor types
computed purely from the three selectors — no property types required —
so it is fine to instantiate before the full graph type exists.
Example
// Demonstrates the "mutually recursive type" problem that
// adjacency_list_traits solves.
//
// We want an interior edge property whose value is a vertex_descriptor
// (for example, a pointer-to-predecessor stored on each edge). That
// requires the vertex_descriptor type to be known BEFORE we finish
// declaring the graph — which is impossible with graph_traits because
// graph_traits needs the full graph type.
//
// adjacency_list_traits<EdgeList, VertexList, Directed> exposes just
// vertex_descriptor / edge_descriptor without instantiating the full
// adjacency_list template, breaking the cycle.
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
using namespace boost;
// Step 1: pre-declare the traits. Same selectors as the final graph.
using Traits = adjacency_list_traits<vecS, vecS, directedS>;
// Step 2: use Traits::vertex_descriptor as a property value type.
using Graph = adjacency_list<
vecS, vecS, directedS,
no_property,
property<edge_name_t, Traits::vertex_descriptor>>;
int main() {
Graph g(3);
auto e01 = add_edge(0, 1, g).first;
auto e12 = add_edge(1, 2, g).first;
// Store the predecessor vertex on each edge.
put(edge_name, g, e01, vertex(0, g));
put(edge_name, g, e12, vertex(1, g));
for (auto e : make_iterator_range(edges(g))) {
std::cout << source(e, g) << " -> " << target(e, g)
<< " predecessor=" << get(edge_name, g, e) << '\n';
}
}
0 -> 1 predecessor=0
1 -> 2 predecessor=1
Observe that Traits and the final Graph use the same three
selectors (vecS, vecS, directedS). If they diverge, the descriptor
types also diverge and the program is ill-formed.
For most use cases, an external predecessor map —
std::vector<vertex_descriptor> wrapped in iterator_property_map — is
simpler and every BGL algorithm already accepts one. Reach for
adjacency_list_traits only when you genuinely need the property to
travel with the graph (serialization, subgraph adaptors, mixing with
GraphML I/O that round-trips interior properties, …).
|
Synopsis
namespace boost {
template <class EdgeList = vecS,
class VertexList = vecS,
class Directed = directedS>
struct adjacency_list_traits {
typedef /* implementation-defined */ vertex_descriptor;
typedef /* implementation-defined */ edge_descriptor;
typedef /* implementation-defined */ directed_category;
typedef /* implementation-defined */ edge_parallel_category;
};
} // namespace boost
Template parameters
| Parameter | Description | Default |
|---|---|---|
|
Selector for per-vertex edge-list storage ( |
|
|
Selector for the vertex container storage. |
|
|
|
|
Members
| Member | Description |
|---|---|
|
Same concrete type as |
|
Likewise for edge descriptors. |
|
|
|
Whether the chosen |
Iterator and size types are not exposed here (they depend on the full
graph type, which has not been declared yet). If you need them, use
graph_traits<Graph> on the completed graph.