Специализировать функцию по классу черт - PullRequest
3 голосов
/ 24 августа 2011

Я пишу хеш-функтор для использования в 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 ]

1 голос
/ 24 августа 2011

Может быть, добавить один параметр шаблона bool в фактический класс EdgeHash? Например:

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)>
{};
1 голос
/ 24 августа 2011

Поместите хеширование в отдельную структуру, ориентированную на тип направленной категории.

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);
    }
};
1 голос
/ 24 августа 2011

Используя 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;
    }
};
...