2014-03-24 70 views
3

嗨堆棧交換專家,Boost:將指針存儲在向量中的分佈

我想收集指向不同的統計分佈提供的Boost在一個向量中。 如果分佈會從一個(虛擬)父類中導出可以寫像

std::vector<Parent> v; 

boost::math::normal_distribution<double> n; 
boost::math::students_t_distribution<float> t(4); 

boost::math::normal_distribution<double> *p1 = new boost::math::normal_distribution<double>(n); 
boost::math::students_t_distribution<float> *p2 = new boost::math::students_t_distribution<float>(t); 
v.push_back(p1); 
v.push_back(p2); 

,然後迭代向量和應用功能等來解除引用指針。 但由於這是不是我真的不知道如何指針存儲在一個地方的情況?因此,我的問題是,如果有一種方法可以將指向不同模板類的指針存儲在一個變量/列表/矢量中(可以像std :: vector一樣方便地處理)。

注意,例如Boost pdf密度函數可以應用於解除引用的指針,而不管特定的類型(因此將它們存儲在一個向量中在某些情況下有意義)。

////////////////////////////////////////////// ////////////////////////////

我玩過各種不錯的答案,最後決定堅持提升: :與boost :: static_visitor結合使用。 下面是一個完整的應用程序,做什麼,我在我原來的問題概括:

#include <boost/math/distributions.hpp> 
#include <boost/variant.hpp> 
#include <vector> 
#include <iostream> 

//template based visitor to invoke the cdf function on the distribution 
class cdf_visitor_generic : public boost::static_visitor<double> 
{ 
    public: 

     //constructor to handle input arguments 
    cdf_visitor_generic(const double &x) : _x(x) {} 

    template <typename T> 
    double operator()(T &operand) const { 
    return(boost::math::cdf(operand,_x)); 
    } 

    private: 
    double _x; 
}; 

//shorten typing 
typedef boost::variant< boost::math::normal_distribution<double>, boost::math::students_t_distribution<double> > Distribution; 

int main (int, char*[]) 
{ 
//example distributions 
boost::math::normal_distribution<double> s; 
boost::math::students_t_distribution<double> t(1); 

//build a variant 
Distribution v = t; 

//example value for evaluation 
double x = 1.96; 

//evaluation at one point 
double y = boost::apply_visitor(cdf_visitor_generic(x),v); 
std::cout << y << std::endl; 


//build a vector and apply to all elements of it: 
std::vector<Distribution> vec_v; 

vec_v.push_back(s); 
vec_v.push_back(t); 


for (std::vector<Distribution>::const_iterator iter = vec_v.begin(); iter != vec_v.end(); ++iter){ 

    //apply cdf to dereferenced iterator 
    double test = boost::apply_visitor(cdf_visitor_generic(x), *iter); 
    std::cout << test << std::endl; 
} 
return 0; 
} 

我看到的唯一的缺點是需要分配的類型必須明確指定(在變型),所以它可能是提振::任何增加更多的自由。

感謝您的幫助很大!

Hank

回答

3

您可以使用variant

std::vector<boost::variant< 
    boost::math::normal_distribution<double>, 
    boost::math::students_t_distribution<float> 
> > v; 

boost::math::normal_distribution<double> n; 
boost::math::students_t_distribution<float> t(4); 

v.push_back(n); 
v.push_back(t); 

我有幾個答案,說明如何使用這些元素「多態「(雖然多態是通過靜態編譯typeswitching,而不是vtable dispatch)。我會盡快添加一個或兩個鏈接。

一些鏈接的回答顯示出 「手工」 的方式來輸入擦除

PS。我也許應該提到boost::any,但我不喜歡它有幾個原因。我不會爲此推薦它。

+0

添加了更多詳細示例的鏈接 – sehe

0

您不能在單個向量中存儲指向不相關類型的指針。實現這一目標的一個方法是使的無效*載體:

std::vector<void*> 

但我強烈建議你這樣做,因爲這是沒有太大的C++的方式。

更好的解決辦法是用於存儲不同類型的指針,例如創建自定義的類層次結構:

class DistributionBase { 
public: 
    virtual ~DistributionBase() {} 
} 

template<typename T> 
class Distribution : public DistributionBase { 
public: 
    typedef T DistributionType; 
    T* distribution; 

    Distribution(T* d) : distribution(d) {} 
    ~Distribution() { delete distribution; } 
} 


template<typename T> 
Distribution<T>* make_distribution(T* d) { 
    return new Distribution<T>(d); 
} 

然後你就可以按如下方式使用它:

std::vector<DistributionBase*> distributions; 
distributions.push_back(make_distribution(new boost::math::normal_distribution<double>(n))) 
distributions.push_back(make_distribution(new boost::math::students_t_distribution<float>(n))) 

的問題是,您必須將分配類型存儲在某處,以便您可以static_cast更正類型:

boost::math::normal_distribution<double>* d = static_cast< Distribution<boost::math::normal_distribution<double> > >(distributions[0])->distribution; 

這只是一個片段,應該告訴你這一點不是一個完整的例子。

+1

這是一個好的開始,但是這種說法並不是很準確。在覈心語言層面,是的,這是不可能的。但是在推動中有非常廣泛使用的設施可以使這種情況發生。 – sehe

+0

嗯,我沒有說這是不可能的,只是在純C++中,你不能交換不同類型的兩個指針。但是,當然總是(不只是一個)解決方案。 – mrate

0

您可以環繞你的公共基類指針。在這裏,我將使用模板方法模式:

class Distribution { 
public: 
    double pdf(double d) { doPdf(d)}; 
private: 
    virtual double doPdf(double d) {} = 0; 
    virtual ~Distribution() {} 
}; 

class NormalDistribution : public Distribution { 
private: 
    boost::math::normal_distribution<double> nd; 
    double doPdf(double d) { return pdf(nd, d);} 
}; 

class StudentsTDistribution : public Distribution { 
private: 
    boost::math::students_t_distribution<double> std; 
    double doPdf(double d) { return pdf(std, d);} 
}; 

用法:

std::vector< boost::shared_ptr<Distribution> > v; 
v.push_back(boost::make_shared<NormalDistribution>()); 
v.push_back(boost::make_shared<StudentsTDistribution>()); 
v[0]->pdf(0.5); // draw from Gauss's distribution 
v[1]->pdf(0.5); // draw from fatter tails - t Student distribution