Funktions-Pointer hier wegoptimierbar??



  • Hallo,
    mir ist gerade die Frage in den Sinn gekommen, was hiervon wohl schneller bzw besser optimierbar ist. Es geht einfach darum je nach Modus verschiedene Funktionen ("func_n") aufzurufen. Und out() soll wesentlich häufiger als setFunc() aufgerufen werden, also zeitkritisch sein..:

    struct C0{
    	T func1(T);
    	T val1;
    	T func2(T);
    	T val2;
    	// ...
    
    	funcPtr ptr;
    	T val;
    
    	T wrap(T x){ return ptr(x)*9857238578923578.01+val*x; }
    
    public:
    	void setFunc(int n){ 
    		switch(n){
    		case0/1/..: ptr = func0/1/..; val = val0/1/..;
    		}
    	}
    
    	T out(T x){ return wrap(x)+wrap(x+sin(x)); }
    };
    
    struct C1{
    	T func1();
    	T val1;
    	T func2();
    	T val2;
    	// ...
    
    	int n;
    
    	T wrap(T x, funcPtr ptr, T val){return ptr(x)*9857238578923578.01+val*x; }
    
    public:
    	void setFunc(int nn){ n = nn; }
    
    	T out(T x){
    		switch(n){
    		case0/1/..: return wrap(x, func0/1/.., val0/1/..)+wrap(x+sin(x), func0/1/.., val0/1/..));
    		}
    	}
    };
    

    Also mir persönlich gefällt C0 besser, aber mein Bauchgefühl sagt mir, dass, wenn überhaupt, C1 (genauer die out() ) eher optimierbar ist, weil da die Argumente der wrap() quasi manuell eingetragen wurden.. Andererseits hat C0 kein switch() in der out().
    Hat jemand eine Meinung dazu, oder eine Idee, auch wenns was ganz anderes ist..



  • Mir entgeht grad ehrlich gesagt der Unterschied.

    Ob du den Funktionszeiger speicherst oder als Parameter übergibst? Kannst du nochmal den Kernaspekt deiner Frage hervorheben?



  • Also wenn ich mich richtig erinnere, kann der Compiler doch Funktions-Pointer im Idealfall direkt durch die Funktionen ersetzen..
    Und ich hätte jetzt angenommen, dass das bei C1 eher geht, da alles wichtige in einer Funktion ( out() ) passiert..

    Wie gewichtig ist eigentlich das switch() in der out (angenommen es kommen noch ein paar Fälle dazu); wird das auch ge-branch-predicted?! Oder ist es besser Funktionspointer in Kauf zu nehmen damit man nicht jedesmal switch() in der out() aufrufen muss!?



  • Messen?



  • manni66 schrieb:

    Messen?

    +1

    Ansonsten, Funktionszeiger werden oft leider nicht wegoptimiert. Zumindest Visual Studio kriegt das meist selbst bei trivialen Fällen nicht hin. Eine Template Variante mit einem Functor wird hingegen viel eher wegoptimiert.



  • Naja wenn sonst nichts bleibt, dann halt messen.. Ich hatte auf irgendwas wie einen allgemein gültigen Merksatz gehofft.
    Ja an Templates hatte ich auch schon gedacht, aber in meiner Fantasie, sprich Bauchgefühl, hatte ich da nicht so groe Chancen gesehen.

    Eine Template Variante mit einem Functor wird hingegen viel eher wegoptimiert.

    Nur zur Sicherheit, du meinst doch einen Pointer auf einen Funktor (evtl gibt es ja noch ganz anderen Möglichkeiten mit Funktoren..)?!
    Jedenfalls schon mal Danke!



  • Ritörn schrieb:

    Nur zur Sicherheit, du meinst doch einen Pointer auf einen Funktor (evtl gibt es ja noch ganz anderen Möglichkeiten mit Funktoren..)?!

    Nein, keine Zeiger. Irgendsowas:

    template <typename F>
    T wrap(F f)
    {
     f(x);
    }
    
    struct Func1
    {
      T operator()() {}
    };
    


  • Ahhh..

    Also mein Anwendungsbsp. dazu sähe so aus:

    double out = wrap<double, func<double> >(func<double>());
    

    Ist das denn nicht irgendwie schlecht, dass man da ein temporäres func<double> erstellen muss?
    Sieht zumindest seltsam aus.



  • Ritörn schrieb:

    Ist das denn nicht irgendwie schlecht, dass man da ein temporäres func<double> erstellen muss?

    Das wird sehr wahrscheinlich komplett wegoptimiert und nur noch der eigentliche Code geinlined.
    Aber du kannst auch eine statische Funktion execute einbauen und dann F::execute aufrufen.



  • Du kannst auch eine sogenannte LAMBDA-Funktion nutzen, dann wird der Functor automatisch vom Compiler generiert.



  • Oder so, ja.


Log in to reply