2012-10-25 13 views
6

Chciałbym użyć GSL w klasie C++ bez deklarowania funkcji członka jako static. Powodem tego jest fakt, że nie znam ich zbyt dobrze i nie jestem pewien co do bezpieczeństwa wątków. Z tego co przeczytałem, std::function może być rozwiązaniem, ale nie jestem pewien, jak go użyć.jak uniknąć funkcji statycznego członka podczas korzystania z gsl z C++

Moje pytanie sprowadza się do tego, jak mogę usunąć static w deklaracji g?

#include<iostream> 
#include <functional> 
#include <stdlib.h> 
#include <gsl/gsl_math.h> 
#include <gsl/gsl_monte.h> 
#include <gsl/gsl_monte_plain.h> 
#include <gsl/gsl_monte_miser.h> 
#include <gsl/gsl_monte_vegas.h> 


using namespace std; 

class A { 
public: 
    static double g (double *k, size_t dim, void *params) 
    { 
    double A = 1.0/(M_PI * M_PI * M_PI); 
    return A/(1.0 - cos (k[0]) * cos (k[1]) * cos (k[2])); 
    } 
    double result() { 
    double res, err; 

    double xl[3] = { 0, 0, 0 }; 
    double xu[3] = { M_PI, M_PI, M_PI }; 

    const gsl_rng_type *T; 
    gsl_rng *r; 

    ////// the following 3 lines didn't work /////// 
    //function<double(A,double*, size_t, void*)> fg; 
    //fg = &A::g; 
    //gsl_monte_function G = { &fg, 3, 0 }; 
    gsl_monte_function G = { &g, 3, 0 }; 

    size_t calls = 500000; 

    gsl_rng_env_setup(); 

    T = gsl_rng_default; 
    r = gsl_rng_alloc (T); 

    { 
     gsl_monte_plain_state *s = gsl_monte_plain_alloc (3); 
     gsl_monte_plain_integrate (&G, xl, xu, 3, calls, r, s, &res, &err); 
     gsl_monte_plain_free (s); 
    } 

    gsl_rng_free (r); 
    return res; 
    } 
}; 

main() { 
    A a; 
    cout <<"gsl mc result is " << a.result() <<"\n"; 
} 

Update (1):

Próbowałem zmieniając gsl_monte_function G = { &g, 3, 0 }; do gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 }; ale to nie działa

Update (2): Próbowałem za pomocą assigning std::function to a member function ale nie zrobił” t działa.

Update (3) w końcu napisałem funkcję trzeciego:

double gmf (double *k, size_t dim, void *params) { 
    auto *mf = static_cast<A*>(params); 
    return abs(mf->g(k,dim,params)); 
    //return 1.0; 
}; 

to działało ale to niechlujny rozwiązaniem, ponieważ musiałem napisać funkcję pomocnika. Z lambdami, funkcją i powiązaniem, powinien istnieć sposób, aby wszystko było logiczne w klasie.

+0

wiem, że moja odpowiedź przyszła dość późno, ale mam nadzieję, że klasa okład może pomóc w przyszłości. Ta okładka jest bardzo przydatna, ponieważ pozwala również na integrację funkcji lambda lub wiązanie funkcji z więcej niż jednym parametrem (jeśli chcesz zintegrować f (x, a) = a x gdzie a jest parametrem na przykład). –

Odpowiedz

7

można łatwo owinąć funkcji składowych za pomocą następującego kodu (co jest dobrze znane rozwiązanie)

class gsl_function_pp : public gsl_function 
{ 
    public: 
    gsl_function_pp(std::function<double(double)> const& func) : _func(func){ 
     function=&gsl_function_pp::invoke; 
     params=this; 
    }  
    private: 
    std::function<double(double)> _func; 
    static double invoke(double x, void *params) { 
    return static_cast<gsl_function_pp*>(params)->_func(x); 
    } 
}; 

Następnie można użyć std :: wiążą się zawinąć funkcji członka w std :: funkcji. Przykład:

gsl_function_pp Fp(std::bind(&Class::member_function, &(*this), std::placeholders::_1)); 
gsl_function *F = static_cast<gsl_function*>(&Fp);  

Jednak należy pamiętać o karach wydajności std :: funkcję przed owijania funkcji składowych wewnątrz rutynowych integracji GSL. Zobacz template vs std::function.Aby tego uniknąć trafień wydajności (które mogą lub nie mogą być krytyczne dla ciebie), należy użyć szablonów, jak pokazano poniżej

template< typename F > 
    class gsl_function_pp : public gsl_function { 
    public: 
    gsl_function_pp(const F& func) : _func(func) { 
    function = &gsl_function_pp::invoke; 
    params=this; 
    } 
    private: 
    const F& _func; 
    static double invoke(double x, void *params) { 
    return static_cast<gsl_function_pp*>(params)->_func(x); 
    } 
}; 

W tym przypadku, aby wywołać funkcję składową potrzebne są następujące

Class* ptr2 = this; 
auto ptr = [=](double x)->double{return ptr2->foo(x);}; 
gsl_function_pp<decltype(ptr)> Fp(ptr);  
gsl_function *F = static_cast<gsl_function*>(&Fp); 

PS: link template vs std::function wyjaśnia, że ​​kompilator zazwyczaj ma łatwiejszy czas na optymalizację szablonów niż std :: function (co jest krytyczne dla wydajności, jeśli twój kod wykonuje ciężkie obliczenia numeryczne). Więc nawet trudne obejście tego drugiego przykładu wydaje się bardziej uciążliwe, wolałbym szablony niż std :: function.

+0

To dobre rozwiązanie, ale wciąż używa statycznych funkcji składowych. tak czy inaczej, zaznaczam to jako odpowiedź, by zamknąć pytanie. Odsunąłem się od Gsl i używam odint teraz, więc nie przetestowałem tego. –

0

Dlaczego martwisz się o funkcję statyczną w tym przypadku? Zmienne i/lub obiekty zadeklarowane w funkcji statycznej nie są współdzielone między różnymi wątkami, chyba że same są statyczne (a w twoim przypadku nie są).

Czy Twój kod nie robi czegoś?

+0

nie teraz, ale jest częścią większego kodu, który będę dalej rozbudowywał. Używam teraz statycznego, ale wolałbym mieć rozwiązanie niestatyczne. Inną korzyścią byłoby zrozumienie "bind" i "function' –

0

Przepraszam, ale to, co próbujesz zrobić, nie ma żadnego sensu. Niezależnie od problemów związanych z bezpieczeństwem wątków, które Cię martwią, nie zostaną rozwiązane przez dodanie lub usunięcie słowa kluczowego static.

Jedyny powód, dla którego g byłby niestatyczny, byłby wtedy, gdyby instancja A była w jakiś sposób wymagana do działania g. Obecna implementacja g nie wymaga takiej instancji.

Uwaga: można również wprowadzić g jako funkcję globalną, bez słowa kluczowego static. W twoim przypadku nie byłoby widocznej różnicy. Jednak w twoim przypadku lepszym stylem jest g w klasie, która korzysta z niego jako funkcja statyczna.

Również, Here jest pokrewnym materiałem na temat wskaźników do funkcji statycznych/niestatycznych.

+0

w moim pełnym kodzie, funkcja' g' zależy od 'std :: function' member. Wystąpił błąd, jeśli wykonam statyczne 'nieprawidłowe użycie elementu ... w statycznej funkcji członka '. wtedy muszę zrobić to 'std :: function' static ale wtedy mam problem z przypisaniem mu funkcji z innej klasy. –

Powiązane problemy