我有一堆boost::property_map
来定义图中边缘遍历的成本。我正在使用这些地图的不同加权组合执行算法,目前通过手动执行totalcost = weight1*weight1_factor + weight2*weight2_factor + ...
。虽然房产地图的数量正在上升,但是这样做总结起来很麻烦。
所以,我设想创建一个聚合类,它包含一些所有地图的集合。但是,它们的模板形式不同,如boost::property_map<Graph, PropertyTag>
,其中PropertyTag
在地图之间有所不同。既然他们都支持operator[](edge_escriptor)
,我可以使用一些技巧,还是我注定要使用boost::any
?
答案 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();
}