Search code examples
c++type-traitsboost-graph

Accessing graph bundle property type, to use it in SFINAE


I have some code that can handle different types of (boost)graphs, and I want to do something special for graphs having some specific bundle property.

For example, this:

struct VertexProp
{
    // some data
};

My code can use two types of graphs:

using graph1_t  = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::undirectedS,
    VertexProp
    > ;

or

using graph2_t = boost::adjacency_list<
    boost::vecS,
    boost::vecS,
    boost::undirectedS
    > ;

My intent is to use SFINAE to enable a function that will only handle this specific case:

template<Graph_t>
void foo
(
    const Graph_t& gr,
    std::enable_if<
        std::is_equal<SOME_TRAIT<Graph_t>::type,VertexProp>,T
        >::type* = nullptr
)
{
    // do something only for graphs having VertexProp
}

I'm ok with type traits in the general case (at least, I think so...), but in this case it's a third party type (boost::adjacency_list).

And I can't find in the provided traits the typedef giving me that type. I also checked the included code in the manual, but didn't help.

How can I access that type ?


Solution

  • You can get the type via the property_map trait. In fact the value-type is a trait of that property map :)

    So to detect the vertex bundle:

    template <typename Graph, typename Bundle = typename boost::property_map<Graph, boost::vertex_bundle_t>::type>
        using VBundle = typename boost::property_traits<Bundle>::value_type;
    

    Making that more readable with whitespace:

    template <
        typename Graph,
        typename Bundle = 
            typename boost::property_map<Graph, boost::vertex_bundle_t>::type>
    using VBundle =
        typename boost::property_traits<Bundle>::value_type;
    

    You can see that we ask the property_traits of the vertex_bundle_t property-map.

    To check that it is the expected type:

    template <typename Graph>
        using HasVertexProp = std::is_same<VertexProp, VBundle<Graph> >;
    

    Now you can use SFINAE. Or, as I'd sugegst for a case like this: tag dispatch;

    namespace detail {
        template <typename Graph_t>
        void foo(const Graph_t& g, std::true_type) {
            print_graph(g, std::cout << "Graph with VertexProp bundle: ");
        }
    
        template <typename Graph_t>
        void foo(const Graph_t& g, std::false_type) {
            print_graph(g, std::cout << "Graph with other/missing properties: ");
        }
    }
    
    template <typename Graph_t>
    void foo(const Graph_t& g) {
        detail::foo(g, HasVertexProp<Graph_t>{});
    }
    

    Let's test it:

    Live On Coliru

    int main() {
        graph1_t g1(4);
        graph2_t g2(4);
        foo(g1);
        foo(g2);
    }
    

    Prints

    Graph with VertexProp bundle: 0 <--> 
    1 <--> 
    2 <--> 
    3 <--> 
    Graph with other/missing properties: 0 <--> 
    1 <--> 
    2 <--> 
    3 <-->