模板异构类型的集合

时间:2011-08-25 14:56:54

标签: c++

我有一堆boost::property_map来定义图中边缘遍历的成本。我正在使用这些地图的不同加权组合执行算法,目前通过手动执行totalcost = weight1*weight1_factor + weight2*weight2_factor + ...。虽然房产地图的数量正在上升,但是这样做总结起来很麻烦。

所以,我设想创建一个聚合类,它包含一些所有地图的集合。但是,它们的模板形式不同,如boost::property_map<Graph, PropertyTag>,其中PropertyTag在地图之间有所不同。既然他们都支持operator[](edge_escriptor),我可以使用一些技巧,还是我注定要使用boost::any

2 个答案:

答案 0 :(得分:2)

我建议您使用属性映射和因子创建boost::tuple

鉴于在你的上下文中,你有每个i的(propertymap_i,weight_i),创建一个聚合类,当被问到时,它使用这个元组(作为聚合类的模板参数)来计算所需的值。

您可以使用operator []或属性映射提供的get()函数。

如果需要,我可能会更清楚,但它必须等一下。

编辑:这接近你需要的吗?

#include <boost/graph/adjacency_list.hpp>
#include <iostream>
#include <boost/shared_ptr.hpp>

namespace property_aggregator
{
  template<typename Tuple, typename T>
  struct helper
  {
      double operator()(Tuple const& tuple, T t)
      {
          return boost::get<0>(tuple)*get(boost::get<1>(tuple), t) +
              helper<typename Tuple::tail_type::tail_type, T>()(tuple.get_tail().get_tail(), t);
      }
  };

  template<typename T>
  struct helper<boost::tuples::null_type, T>
  {
      double operator()(boost::tuples::null_type const& tuple, T t)
      {
          return 0.;
      }
  };

  template<typename T>
  class BasePropertyAggregator
  {
  public:
    virtual double compute( T t ) = 0;
  };

  template <typename PropertyTuple, typename T> 
  class PropertyAggregator : public BasePropertyAggregator<T>
  {
  public:
      PropertyAggregator(PropertyTuple const& tuple) : m_tuple(tuple){}
      virtual ~PropertyAggregator(){}

      double compute( T t )
      {
          return property_aggregator::helper<PropertyTuple, T>()(m_tuple, t);
      }


  private:
      PropertyTuple m_tuple;

  };
}

template<typename T>
class PropertyAggregator
{
public:
    template<typename Tuple>
    PropertyAggregator(Tuple const& tuple) : m_computer(new property_aggregator::PropertyAggregator<Tuple, T>(tuple))
    {}

    double operator()(T t)
    {
      return m_computer->compute(t);
    }

private:
  boost::shared_ptr<property_aggregator::BasePropertyAggregator<T> > m_computer;
};

// Defaut type of a graph
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
  boost::property<boost::vertex_index_t, unsigned int>,
  boost::property<boost::edge_weight_t, double,
     boost::property<boost::edge_color_t, double> > > Graph;

int main()
{
    typedef boost::property_map<Graph, boost::edge_weight_t>::type PM1;
    typedef boost::property_map<Graph, boost::edge_color_t>::type PM2;
    typedef boost::graph_traits<Graph>::edge_descriptor EdgeType;

    Graph g;
    PM1 pm1 = get(boost::edge_weight, g);
    PM2 pm2 = get(boost::edge_color, g);

    add_vertex(g);
    add_vertex(g);
    EdgeType edge1 = boost::add_edge(0, 1, g).first;
    put(pm1, edge1, 1.);
    put(pm2, edge1, 2.);

    typedef PropertyAggregator<EdgeType> ComboType;
    ComboType combo1(boost::make_tuple(1., pm1));
    ComboType combo2(boost::make_tuple(1., pm2));
    ComboType combo3(boost::make_tuple(1., pm1, 2., pm2));
    std::cout << "-- " << combo1(edge1) << std::endl;
    std::cout << "-- " << combo2(edge1) << std::endl;
    std::cout << "-- " << combo3(edge1) << std::endl;

    return 0;
}

答案 1 :(得分:1)

使用纯虚方法创建一个抽象的BasePropertyMap类,以实现常用功能。创建从此基础派生的模板类,并在boost_property_map专门化上进行模板化。在派生的模板类型中,按指针或值保存property_map,并使用模板化属性映射的代码覆盖基类虚拟。根据需要进行专业化。

然后,您可以动态创建派生类型对象,并通过基类指针将它们保存在集合中。

假设你,例如想要总结所有属性贴图的权重,你可以编写一个模板函数来计算单个属性贴图的权重,它会是这样的:

template<typename Graph, typename PropertyTag>
double calc_weight(const boost::property_map<Graph, PropertyTag>& propMap) {
    // your body here
}

class BasePropertyMap {
    virtual double weight() = 0;
}

template<typename Graph, typename PropertyTag>
class DerivedPropertyMap: public BasePropertyMap {
    boost::property_map<Graph, PropertyTag> my_map;
    double weight() {
        return calc_weight(my_map);
    }
}

std::vector<BasePropertyMap*> collection;

[...]
// iterate over collection
totalcost=0;
for(auto it=collection.begin(), endit = collection.end(); it!=endit; ++it) {
    totalcost += (*it)->weight();
}