Concepts play a central role in generic programming, and are the interface definitions that allow many different components to be used with the same algorithm. The Boost Graph Library defines a large collection of concepts that cover various aspects of working with a graph, such as traversing a graph or modifying its structure. In this chapter, we introduce these concepts and also provide some motivation for the choice of concepts in the BGL.

This sample chapter is excerpted from The Boost Graph Library: User Guide and Reference Manual, by Jeremy Siek, Lie-Quan Lee, and Andrew Lumsdaine.

This chapter is from the book

As discussed in the previous chapter, concepts play a central role in
generic programming. Concepts are the interface definitions that allow many
different components to be used with the same algorithm. The Boost Graph Library
defines a large collection of concepts that cover various aspects of working
with a graph, such as traversing a graph or modifying its structure. In this
chapter, we introduce these concepts and also provide some motivation for the
choice of concepts in the BGL.

From the description of the generic programming
process (see page 19), concepts are derived from the algorithms that are used to
solve problems in particular domains. In this chapter we examine the problem of
tracking file dependencies in a build system. For each subproblem, we examine
generalizations that can be made to the solutions, with the goal of increasing
the reusability (the genericity) of the solution. The result, at the end of the
chapter, is a generic graph algorithm and its application to the file-dependency
problem.

Along the way, we also cover some of the more
mundane but necessary topics, such as how to create a graph object and fill in
the vertices and edges.

3.1 File Dependencies

A common use of the graph abstraction is to represent dependencies. One
common type of dependency that we programmers deal with on a routine basis is
that of compilation dependencies between files in programs that we write.
Information about these dependencies is used by programs such as make, or
by IDEs such as Visual C++, to determine which files must be recompiled to
generate a new version of a program (or, in general, of some target) after a
change has been made to a source file.

Figure 3.1 shows a graph that has a vertex for
each source file, object file, and library that is used in the killerapp
program. An edge in the graph shows that a target depends on another target
in some way (such as a dependency due to inclusion of a header file in a source
file, or due to an object file being compiled from a source file).

Answers to many of the questions that arise in
creating a build system such as make can be formulated in terms of the
dependency graph. We might ask these questions:

If all of the targets need to be made, in what order should that be
accomplished?

Are there any cycles in the dependencies? A dependency cycle is an error,
and an appropriate message should be emitted.

How many steps are required to make all of the targets? How many steps
are required to make all of the targets if independent targets are made
simultaneously in parallel (using a network of workstations or a multiprocessor,
for example)?

In the following sections these questions are
posed in graph terms, and graph algorithms are developed to provide solutions.
The graph in Figure 3.1 is used in all of the examples.