Collection of template heterogeneous types

I have a boost::property_map group that defines the cost of going around the edge of the chart. I am running an algorithm with difference-weighted combinations of these cards, currently manually doing totalcost = weight1*weight1_factor + weight2*weight2_factor + ... The number of property maps is growing, although it is becoming a problem to summarize them as follows.

So, I foresaw the creation of an aggregation class that contains a collection of some all the cards. However, they are templates in different ways, like boost::property_map<Graph, PropertyTag> , where the PropertyTag is different from the maps. Since they all support operator[](edge_escriptor) , is there any trick I can use, or am I doomed to use boost::any ?

+4
source share
2 answers

I would advise you to create boost :: tuple with property maps and factors.

Given that in your context you have (propertymap_i, weight_i) for each i, create an aggregation class that uses this tuple (as a template parameter for the aggregation class) to calculate the required value when asked.

You can use the [] operator or the get () function provided by property maps.

I may perhaps be clearer if necessary, but need to wait a bit.

EDIT: Is this close to what you need?

 #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; } 
+2
source

Create an abstract BasePropertyMap class using simple virtual methods for common functionality. Create a template class that is derived from this database and configured for your specialty boost_property_map. In your derived template type, hold the property_map property with a pointer or value and override the virtual classes of the base class with the code for your template property map. Specialize as needed.

Then you can dynamically create objects of a derived type and hold them in your collection using the base class pointer.

Assuming you, for example. If you want to summarize the weight of all your property cards, and you can write a template function to calculate the weight of one property map, it will look something like this:

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

Source: https://habr.com/ru/post/1368978/


All Articles