模板异构类型的集合

Collection of template-heterogeneous types

本文关键字:集合 类型 异构      更新时间:2023-10-16

我有一堆boost::property_map s定义了图中遍历边的代价。我正在执行一个算法与这些地图的不同加权组合,目前通过手动做totalcost = weight1*weight1_factor + weight2*weight2_factor + ...。然而,属性映射的数量正在增加,像这样总结它们变得很麻烦。

因此,我设想创建一个聚合类,它包含某种类型的所有映射的集合。然而,它们的模板是不同的,如boost::property_map<Graph, PropertyTag>,其中PropertyTag在地图中是不同的。既然它们都支持operator[](edge_escriptor),那么我是否可以使用一些技巧,或者我注定要使用boost::any ?

我建议你创建一个包含属性映射和因子的boost::元组

考虑到在您的上下文中,对于每个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;
}

创建一个抽象的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();
}