2012-10-25 11 views
6

Ich möchte GSL innerhalb einer C++ - Klasse ohne Deklaration Memberfunktionen wie static. Der Grund dafür ist, dass ich sie nicht gut kenne und ich bin mir nicht sicher über die Sicherheit von Fäden. Von dem, was ich gelesen habe, std::function könnte eine Lösung sein, aber ich bin mir nicht sicher, wie man es benutzt.Wie zu vermeiden, statische Member-Funktion bei der Verwendung von GSL mit C++

Meine Frage kommt zu, wie kann ich static in der Erklärung von g entfernen?

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

Ich versuchte gsl_monte_function G = { &g, 3, 0 };-gsl_monte_function G = { bind(&A::g, this,_1,_2,_3), 3, 0 }; ändern, aber es hat nicht funktioniert

Update (2): ich versucht, mit assigning std::function to a member function aber es didn‘ t arbeiten entweder.

Update (3) am Ende habe ich eine Nicht-Mitglied-Funktion:

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

Es funktionierte, aber es ist eine schmutzige Lösung, weil ich eine Hilfsfunktion zu schreiben, benötigt. Mit lambdas, function und bind sollte es einen Weg geben, alles logisch in der Klasse zu haben.

+0

Ich weiß, dass meine Antwort ziemlich spät kam, aber ich hoffe, dass Wrap Klasse, die Ihnen in der Zukunft helfen kann. Dieser Wrap ist sehr praktisch, da er auch die Integration von Lambda-Funktionen oder das Binden von Funktionen mit mehr als einem Parameter ermöglicht (wenn Sie f (x, a) = a x integrieren wollen, wobei a beispielsweise ein Parameter ist). –

Antwort

7

Sie können ganz einfach Member-Funktionen mit dem folgenden Code wickeln (die eine bekannte Lösung ist)

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

Dann können Sie std :: bind wickeln die Member-Funktion in einer std :: Funktion verwenden. Beispiel:

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

Sie sollten jedoch über die Leistungseinbußen von std :: Funktion bewusst sein, bevor Mitgliederfunktionen innerhalb GSL Integrationsroutine wickeln. Siehe template vs std::function.Um diese Leistungseinbußen zu vermeiden (die Sie kann oder auch nicht kritisch sein), dann sollten Sie Vorlagen verwenden, wie unten

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

In diesem Fall gezeigt, eine Memberfunktion aufzurufen benötigen Sie bitte den folgenden

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: Der Link template vs std::function erklärt, dass es dem Compiler normalerweise leichter fällt, Vorlagen zu optimieren als std :: function (was für die Performance entscheidend ist, wenn Ihr Code eine starke numerische Berechnung durchführt). Selbst wenn die Problemumgehung im zweiten Beispiel mühsamer erscheint, würde ich Templates lieber als std :: function vorziehen.

+0

Es ist eine gute Lösung, aber es verwendet immer noch statische Elementfunktionen. Wie auch immer, ich markiere es als beantwortet, um die Frage zu schließen. Ich entfernte mich von GSL und benutze Odein jetzt, also habe ich es nicht getestet. –

0

Warum machen Sie sich in diesem Fall Gedanken über die statische Funktion? Variablen und/oder Objekte, die in einer statischen Funktion deklariert sind, werden nicht zwischen verschiedenen Threads geteilt, es sei denn, sie sind selbst statisch (was in Ihrem Fall nicht der Fall ist).

Kann Ihr Code etwas nicht tun?

+0

jetzt nicht, aber es ist ein Teil eines größeren Codes, den ich weiter ausbauen werde. Ich benutze für jetzt statische, aber ich hätte lieber eine nicht-statische Lösung. Ein weiterer Vorteil wäre, zu verstehen "bind" und "function" –

0

Entschuldigung, aber was Sie versuchen, macht keinen Sinn. Was auch immer Thread-Sicherheitsprobleme angeht, um die Sie sich sorgen, sie werden nicht gelöst, indem Sie das Schlüsselwort static hinzufügen oder entfernen.

Der einzige Grund, warum Sie g nicht statisch machen würden, wäre, wenn eine Instanz von A irgendwie für g 's Operation erforderlich wäre. Und die aktuelle Implementierung von g benötigt keine solche Instanz.

Hinweis Sie können auch g eine globale Funktion ohne das Schlüsselwort static machen. In Ihrem Fall würde es keinen sichtbaren Unterschied geben. Allerdings ist es in Ihrem Fall besser, g in der Klasse zu verwenden, die es als statische Funktion verwendet.

Auch Here ist etwas verwandtes Material über Zeiger auf (statische/nicht-statische) Elementfunktionen.

+0

in meinem vollständigen Code, hängt die 'g' Funktion von' std :: Funktion' Mitglied. Ich erhalte einen Fehler, wenn ich g statische 'ungültiger Gebrauch von Mitglied ... in der statischen Mitgliedsfunktion' mache. dann muss ich diese 'std :: function' statisch machen, aber dann habe ich ein Problem damit, eine Funktion einer anderen Klasse zuzuordnen. –