2011-08-25 49 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(); 
}