2011-08-25 36 views
4

我有一堆boost::property_map定义了图中边缘遍历的代价。我正在执行这些地图的不同加权组合的算法,目前通过手动执行totalcost = weight1*weight1_factor + weight2*weight2_factor + ...。虽然地产地图的数量在不断增加,但像这样总结它们已成为一件麻烦事。模板异构类型的集合

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

回答

2

我会建议你创建一个boost::tuple与财产地图和因素。

考虑到在您的上下文中,每个i都有(propertymap_i,weight_i),请求时创建一个使用此元组的聚合类(作为聚合类的模板参数)来计算所需的值。

您可以使用operator []或property map提供的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; 
} 
+0

我不确定我关注.. 。我需要存储包含元组的聚合类,但现在他们会有不同的模板参数,因此不兼容? – carlpett

+0

在提炼我的答案之前,只是一个简单的问题:你是否定义了所有属性图都是相同类型的?我当然不是在谈论标签类型,而是底层类型。 –

+0

是的,它们都是'boost :: property_map ',其中'Graph'是一个固定的图形类型。 – carlpett

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(); 
}