2014-03-24 4 views
3

안녕하세요 스택 교환 전문가,부스트 : 벡터로 분포에 포인터 저장

나는 하나의 벡터에서 부스트에 의해 제공되는 다른 통계적 분포에 대한 포인터를 수집하려고합니다. 분포가 하나의 (가상) 부모 클래스에서 파생 될 수 경우에 나는

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처럼 편리하게 처리 할 수있는) 다른 템플릿 클래스에 대한 포인터를 저장하는 방법이 있다면 내 질문입니다.

예를 들어 부스트 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; 
} 

내가 볼 수있는 유일한 단점은 분포의 유형 (변형에) 명시 적으로 지정 될 필요가 그래서이 향상 될 수 있다는 것입니다 :: any는 더 많은 자유를 부여합니다.

큰 도움을 가져 주셔서 감사합니다.

행크

답변

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 디스패치 대신 정적으로 유형 전환을 컴파일하는 것이지만). 곧 링크를 추가하겠습니다. Generating an interface without virtual functions?

  • Avoid RTTI when dealing with pairs of objects
  • 더 많은 참여

    링크 된 답변 중 일부는 삭제를

    PS를 입력합니다 "수동"접근 방식을 보여줍니다. 나는 아마도 boost::any을 언급해야하지만 몇 가지 이유 때문에 그것을 싫어한다. 나는이 목적을 위해 그것을 추천하지 않을 것이다.

  • +0

    더 정교한 예제 링크 추가 – sehe

    0

    단일 벡터에 관련없는 유형의 포인터를 저장할 수 없습니다. 이것을 달성하는 한 가지 방법은 * 무효의 벡터 수 있도록하는 것입니다 :

    std::vector<void*> 
    

    을하지만 이것은 C++ 방식의 많은 아니므로 난 강력하게이 일에서 당신을 낙담 것입니다. 문제는

    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))) 
    

    을 :

    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); 
    } 
    

    그리고 다음과 같이 당신은 그것을 사용할 수 있습니다

    더 나은 솔루션은 예를 들어, 포인터의 다른 종류를 저장하는 사용자 정의 클래스 계층 구조를 작성하는 것입니다 어딘가에서 배포 유형을 저장해야 static_cast 유형을 수정할 수 있습니다.

    이것은 완전한 예가 아니라 요점을 보여줄 수있는 스 니펫입니다.

    +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 
    
    관련 문제