2012-04-20 17 views
6

Ich hätte gerne eine Klasse implementieren operator() mehrere verschiedene Möglichkeiten basierend auf einer Option in der Klasse festgelegt. Da dies viele Male aufgerufen wird, möchte ich nichts verwenden, das verzweigt. Im Idealfall wäre der operator() ein Funktionszeiger, der mit einer Methode eingestellt werden kann. Ich bin mir jedoch nicht sicher, wie das eigentlich aussehen würde. Ich habe versucht:Operator als Funktionszeiger

#include <iostream> 

class Test { 
public: 
    int (*operator())(); 

    int DoIt1() { 
    return 1; 
    } 

    int DoIt2() { 
    return 2; 
    } 

    void SetIt(int i) { 
    if(i == 1) { 
     operator() = &Test::DoIt1; 
    } else { 
     operator() = &Test::DoIt2; 
    } 
    } 
}; 

int main() 
{ 
    Test t1; 

    t1.SetIt(1); 

    std::cout << t1() << std::endl; 

    t1.SetIt(2); 

    std::cout << t1() << std::endl; 

    return 0; 
} 

Ich weiß, es wird funktionieren, wenn ich einen anderen Funktionszeiger erstellen und rufen, dass aus der operator() Funktion. Aber ist es möglich, dass die Funktion operator() selbst ein Funktionszeiger ist? Etwas in der Art was ich gepostet habe (was nicht kompiliert)?

Der obige Code gibt:

test.cxx:5:21: error: declaration of ‘operator()’ as non-function

test.cxx: In member function ‘void Test::SetIt(int)’:

test.cxx:17:16: error: ‘operator()’ not defined

test.cxx:19:16: error: ‘operator()’ not defined

test.cxx: In function ‘int main()’:

test.cxx:30:19: error: no match for call to ‘(Test)()’

test.cxx:34:19: error: no match for call to ‘(Test)()’

+0

'int (Operator())();' ... korrekte Syntax? – iammilind

+0

Hrm, sollte es 'int sein (* operator())();' Ich denke, aber das wirft nur eine ganze Reihe von Fehlern. Ich werde den Code bearbeiten. – tpg2114

+0

"Ich möchte nichts verwenden, das verzweigt. Im Idealfall wäre der Operator() ein Funktionszeiger" - Zweige sind eigentlich besser für die Leistung. Moderne CPUs haben eine Erfolgsrate von mehr als 50% bei der Vorhersage, welche Verzweigung genommen wird; Funktionszeiger können überall zeigen und sind daher viel schwieriger für die Vorhersagelogik. – MSalters

Antwort

5

Ihre Klasse muss irgendwie daran zu erinnern, welche Funktion Zeiger zu verwenden. Bewahren Sie es als eine Klasse Mitglied:

class Test 
{ 
public: 
    Test() : func(0) {} 

    int operator()() { 
     // Note that pointers to Test member functions need a pointer to Test to work. 
     return (this->*func)(); // undefined behavior if func == 0 
    } 

    void SetIt(int i) { 
     if(i == 1) { 
      func = &Test::DoIt1; 
     } else { 
      func = &Test::DoIt2; 
     } 
    } 

private: 
    int DoIt1() { 
     return 1; 
    } 

    int DoIt2() { 
     return 2; 
    } 

    // Typedef of a pointer to a class method. 
    typedef int (Test::*FuncPtr)(); 
    FuncPtr func; 
}; 

Bevor Sie jedoch die Mühe gehen in dies zu tun, Profil Code zuerst und sehen, ob Verzweigung über switch oder if tatsächlich ein Engpass ist (es kann nicht sein!). Moderne Prozessoren haben sehr kontraintuitive Leistungsmerkmale, sodass Compiler möglicherweise besseren Code generieren können als Sie denken. Die einzige Möglichkeit, sicherzustellen, dass die Verzweigung für Sie zu teuer ist, besteht darin, Ihren Code zu profilieren. (Und durch "Profiling" meine ich "gut konzipierte Experimente ausführen", nicht "eine Ahnung ohne Test").

+0

'typedef int (* FuncPtr)(); 'ist falsch. Sie müssen schreiben 'typedef int (Test :: * FuncPtr)(); ' – Nawaz

+0

@Nawaz: Fixed. Danke, dass du darauf hingewiesen hast. –

+0

Es gibt immer noch ein Problem. Sie müssen '(this -> * func)();', nicht nur 'func();' schreiben. – Nawaz

1

Sie können Ihre operator() eine Inline-Funktion machen, die einen anderen Zeiger aufruft. Der Optimierer sollte die zusätzliche Indirektion vollständig entfernen.

1

Eine Lösung wird von @In silico bereitgestellt, die in C++ 03 und C++ 11 gültig ist.

Hier ist eine weitere Lösung für C++ 11 nur:

std::function<int(Test*)> func; 

func = &Test::DoIt1; 

func(this); //this syntax is less cumbersome compared to C++03 solution 

A quick online full demo