如何使用BGL的adjacency_list与标准unorunordered_set作为出边列表模板参数

时间:2015-04-12 17:05:20

标签: c++11 boost boost-graph

我正在尝试将boost的图库adjacency_list与C ++ 11 unorunordered_set一起使用。 当使用它作为第二个模板参数(即顶点列表)编译时,当尝试将其用作“外边缘”类型​​(第一个模板参数)时,我收到以下错误: “" C ++标准并没有为这种类型提供哈希。" 以下是有问题的代码:

#include <unordered_set>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>

struct NodeProperty{
    std::string FirstName;
    std::string LastName;
};

namespace std{
    template<>
    struct hash<NodeProperty>
    {
        std::hash<std::string> hasher;
        size_t operator()(const NodeProperty& key) const
        {
            return hasher(key.FirstName) ^ hasher(key.LastName);
        }
    };
}
namespace boost {
    struct std_unorunordered_setS{};

    template <class ValueType>
    struct container_gen<std_unorunordered_setS, ValueType> {
        typedef std::unordered_set<ValueType> type;
    };

    template <>
    struct parallel_edge_traits<std_unorunordered_setS> {
        typedef disallow_parallel_edge_tag type;
    };
}

using namespace boost;

int main(int, char*[])
{
    typedef adjacency_list< std_unorunordered_setS, std_unorunordered_setS, bidirectionalS,
        NodeProperty > Graph;

    typedef graph_traits<Graph>::vertex_descriptor Vertex;
}

许多10倍, 安德烈

1 个答案:

答案 0 :(得分:2)

外边列表确实使用了实现定义的包装类型。

如果你很好地阅读了这个消息,你会发现你需要一个类型擦除的迭代器包装器的哈希值。您需要这些专业化(从detail/adjacency_list.hpp被盗):

namespace std {

    template <typename V> struct hash<boost::detail::stored_edge<V> > {
        std::size_t operator()(const boost::detail::stored_edge<V> &e) const { return hash<V>()(e.m_target); }
    };

    template <typename V, typename P> struct hash<boost::detail::stored_edge_property<V, P> > {
        std::size_t operator()(const boost::detail::stored_edge_property<V, P> &e) const { return hash<V>()(e.m_target); }
    };

    template <typename V, typename I, typename P> struct hash<boost::detail::stored_edge_iter<V, I, P> > {
        std::size_t operator()(const boost::detail::stored_edge_iter<V, I, P> &e) const { return hash<V>()(e.m_target); }
    };
}

CAVEAT :我只使用内置的hash_setS选择器(使用boost::unordered_set)。这样,您就不会依赖明确不在公共标题中的实现细节。

两种口味 Live On Coliru

#include <unordered_set>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>

struct NodeProperty {
    std::string FirstName;
    std::string LastName;
};

namespace std {
    template <> struct hash<NodeProperty> {
        std::hash<std::string> hasher;
        size_t operator()(const NodeProperty &key) const { return hasher(key.FirstName) ^ hasher(key.LastName); }
    };
}

namespace std {
    template <typename V> struct hash<boost::detail::stored_edge<V> > {
        std::size_t operator()(const boost::detail::stored_edge<V> &e) const { return hash<V>()(e.m_target); }
    };

    template <typename V, typename P> struct hash<boost::detail::stored_edge_property<V, P> > {
        std::size_t operator()(const boost::detail::stored_edge_property<V, P> &e) const { return hash<V>()(e.m_target); }
    };

    template <typename V, typename I, typename P> struct hash<boost::detail::stored_edge_iter<V, I, P> > {
        std::size_t operator()(const boost::detail::stored_edge_iter<V, I, P> &e) const { return hash<V>()(e.m_target); }
    };
}

namespace boost {
    struct std_unordered_setS {};

    template <class ValueType> struct container_gen<std_unordered_setS, ValueType> {
        typedef std::unordered_set<ValueType> type;
    };

    template <> struct parallel_edge_traits<std_unordered_setS> { typedef disallow_parallel_edge_tag type; };
}

using namespace boost;

int main() {
#ifdef USE_STD
    typedef adjacency_list<std_unordered_setS, std_unordered_setS, bidirectionalS, NodeProperty> Graph;
#else
    typedef adjacency_list<hash_setS, hash_setS, bidirectionalS, NodeProperty> Graph;
#endif

    // typedef graph_traits<Graph>::vertex_descriptor Vertex;
}