提升:将指针存储到向量中的分布

时间:2014-03-24 15:47:12

标签: c++ pointers boost vector distribution

Hi Stack Exchange Experts,

我正在尝试收集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与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;
}

我看到的唯一缺点是需要明确指定分布类型(在变体中),因此可能是boost :: any增加了更多的自由。

感谢您的大力帮助!

汉克

3 个答案:

答案 0 :(得分: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);

我有几个答案显示如何“多态”使用这些元素(尽管多态性是通过静态编译类型切换,而不是vtable调度)。我很快就会添加一两个链接。

一些链接的答案显示了类型擦除的“手动”方法

<子> PS。我也应该提到boost::any,但出于几个原因我不喜欢它。我不会为此目的推荐它。

答案 1 :(得分:0)

您无法在单个向量中存储指向不相关类型的指针。实现这一目标的一种方法是制作一个void *:

的向量
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;

这只是一个片段,应该向您展示不是一个完整的例子。

答案 2 :(得分: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