由特质类专门化功能

时间:2011-08-24 12:55:44

标签: c++ templates traits

我正在编写一个哈希仿函数,用于boost::unordered_map,它将存储boost::graph边缘描述符。很简单。无向和有向图形边缘必须以不同方式进行散列(至少在我的情况下,边缘(u,v)(v,u)在图表未定向时是等效的,因此map[(u,v)]map[(v,u)]必须指向相同的值)。我可以使用图形特征类(boost::graph_traits<Graph>::directed_category)检测定向性,但是如何使用模板定义不同的实现?

以下是我到目前为止所做的,但我不想要if条款。相反,我希望EdgeHash根据operator()的值编译directed_category的不同版本。如何实现这一目标?

template <typename Graph>
struct EdgeHash {
    typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
    std::size_t operator()(const Edge& e) const {
        std::size_t hash = 0;
        if(boost::is_same<boost::graph_traits<Graph>::directed_category, boost::directed_tag>::value) {
            boost::hash_combine(hash, e.m_source);
            boost::hash_combine(hash, e.m_target);
        } else {
            boost::hash_combine(hash, std::min(e.m_source, e.m_target));
            boost::hash_combine(hash, std::max(e.m_source, e.m_target));
        }
        return hash;
    }
};

3 个答案:

答案 0 :(得分:1)

使用boost::enable_if,您可以执行此操作,但是,您必须专门化结构。例如(未经测试)

template <typename Graph, class Enable = void>
struct EdgeHash {
    typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
    std::size_t operator()(const Edge& e) const {
        std::size_t hash = 0;
        boost::hash_combine(hash, std::min(e.m_source, e.m_target));
        boost::hash_combine(hash, std::max(e.m_source, e.m_target));
        return hash;
    }
};

template <typename Graph>
struct EdgeHash<Graph, typename boost::enable_if<boost::is_same<boost::graph_traits<Graph>::directed_category, boost::directed_tag> >::type>
{
    typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
    std::size_t operator()(const Edge& e) const {
        std::size_t hash = 0;
        boost::hash_combine(hash, e.m_source);
        boost::hash_combine(hash, e.m_target);
        return hash;
    }
};

答案 1 :(得分:1)

可能在实际的EdgeHash类中添加一个bool模板参数?例如:

template <typename Graph, bool is_directed>
struct EdgeHashImpl {
    typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
    std::size_t operator()(const Edge& e) const {
        std::size_t hash = 0;
        boost::hash_combine(hash, e.m_source);
        boost::hash_combine(hash, e.m_target);
    return hash;
   }
};

template <typename Graph>
struct EdgeHashImpl <Graph, false>
{
  typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
  std::size_t operator()(const Edge& e) const {
      std::size_t hash = 0;
      boost::hash_combine(hash, std::min(e.m_source, e.m_target));
      boost::hash_combine(hash, std::max(e.m_source, e.m_target));
      return hash;
   }
};


template <typename Graph>
struct EdgeHash 
: public EdgeHashImpl
  <Graph, boost::is_same<boost::graph_traits<Graph>::directed_category, boost::directed_tag>::value)>
{};

答案 2 :(得分:1)

将散列放在一个单独的结构中,该结构模板化为定向类别类型。

template<typename Directed, typename Edge>
struct Hasher {
    static std::size_t edge_hash(const Edge& e) {
        std::size_t hash = 0;
        boost::hash_combine(hash, e.m_source);
        boost::hash_combine(hash, e.m_target);
        return hash;
    }
};

template<typename Edge>
struct Hasher<boost::directed_tag, Edge> {
    static std::size_t edge_hash(const Edge& e) {
        std::size_t hash = 0;
        boost::hash_combine(hash, std::min(e.m_source, e.m_target));
        boost::hash_combine(hash, std::max(e.m_source, e.m_target));
        return hash;
    }
};

template <typename Graph>
struct EdgeHash {
    typedef typename boost::graph_traits<Graph>::edge_descriptor Edge;
    std::size_t operator()(const Edge& e) const {
        return Hasher<
            boost::graph_traits<Graph>::directed_category,
            Edge>::edge_hash(e);
    }
};