How to solve Boost::BGL template<->class circul

2019-04-12 01:36发布

问题:

I have a problem with using the adjacency-list of the Boost Graphics Library. It seems to be a circular dependency problem: I have a typedef T of a template which uses some class A. Additionally A stores a pointer to an object of type T. Now the compiler tells me, that T does not name a type.

Here are excerptions of my more concrete files:

//graphdefinitions.hpp
#include "lane.hpp"
#include "tie.hpp"

typedef boost::adjacency_list<boost::listS, boost::listS, 
                              boost::directedS, Tie, Lane> Map;
typedef boost::graph_traits<Map>::edge_descriptor edge_descriptor;

//lane.hpp
#include "graphdefinitions.hpp"
class Lane {
    ...
    edge_descriptor *left, *right;
};

//tie.hpp
//no important includes here
class Tie {
    ...
};

How do I solve this dependency / inclusion-order problem?

ANOTHER EDIT: I just had the idea that the type of an edge_descriptor might be a primitive one like int. That would have solved the problem because I would have been able to replace the edge_descriptors of Lane by plain int-variables and thus could have removed the inclusion of graphdefinitions.hpp inside tie.hpp. Unfortunately my idea was cra* and I have to find another solution. Edge_descriptor types seem to be there for a reason...

回答1:

You have circularly included headers. Lane includes graphdefinitions, which includes lane, which includes graphdefinitions, etc. This is the cause of your problem.

Edit: I realized this was already mentioned in the OP. The solution to this problem is PIMPL.

Edit: What I would actually do is put the typedef inside the Lane class. That should solve the problem in the neatest way.



回答2:

There is a not-well-documented traits class in BGL that gives the vertex and edge descriptor types for an adjacency_list graph without needing to know the property types. It is designed for exactly the use case you have. Look in the "Associated Types" section of http://www.boost.org/doc/libs/1_45_0/libs/graph/doc/adjacency_list.html and notice that there are two definitions for vertex_descriptor and edge_descriptor; you can use the versions that come from adjacency_list_traits in the definitions of your property bundles without causing a circular definition.



回答3:

I really don't think you need anything special about this code. You have to make sure the definitions of the types used in the graph are declared (not only forward-declared).



回答4:

@DeadMG: I used a PIMPL-like approach now and I think that this solved my problem.

So what did I do? I changed my Lane-class to look this way:

//lane.hpp
#include "graphdefinitions.hpp"

class LaneSide;
class Lane {
public:
    const LaneSide getLeft() const;
    const LaneSide getRight() const;
    ...
private:
    LaneSide *left;
    LaneSide *right;
    ...
};

And the LaneSide-class which is practically just an indirection and holds the type of value that I could not forward declare inside of lane.hpp, looks this way:

//laneside.hpp
class LaneSide
{
    edge_descriptor* edge;
};

This seems to trick the compiler as I intended to. So thank you for the hint DeadMG. What I was wondering: Is it also possible to store a LaneSide-object inside of the Lane-class not as a pointer but rather as a real object? I tried this first but the compiler complained about the construction. And I'm also wondering whether there might be a way to avoid the additional memory consumption. When my graph gets big enough this might eventually become relevant.