1

Ich mache ein lineares genetisches Programmierungsprojekt, in dem Programme durch natürliche Evolutionsmechanismen gezüchtet und entwickelt werden. Ihre "DNA" ist im Grunde genommen ein Container (ich habe erfolgreich Arrays und Vektoren verwendet), die Funktionszeiger zu einer Reihe von verfügbaren Funktionen enthalten. Jetzt, für einfache Probleme, wie mathematische Probleme, könnte ich einen typdefinierten Funktionszeiger verwenden, der auf Funktionen zeigen könnte, die alle ein Doppel zurückgeben und alle als Parameter zwei Doppel annehmen.Wie erstellt man einen Container, der verschiedene Typen von Funktionszeigern in C++ enthält?

Leider ist das nicht sehr praktisch. Ich muss in der Lage sein, einen Container zu haben, der verschiedene Arten von Funktionszeigern haben kann, zB einen Funktionszeiger auf eine Funktion, die keine Argumente annimmt, oder eine Funktion, die ein Argument benötigt, oder eine Funktion, die etwas zurückgibt Idee) ...

Gibt es eine Möglichkeit, dies mit jeder Art von Container zu tun? Könnte ich das tun, indem ich einen Container verwende, der polymorphe Klassen enthält, die wiederum verschiedene Arten von Funktionszeigern haben? Ich hoffe, dass jemand mich zu einer Lösung führen kann, weil das Umgestalten alles was ich bis jetzt getan habe, wird schmerzhaft sein.

+0

Angenommen, Sie haben einen Container 'c' mit vielen verschiedenen Funktionen. Wie wirst du sie anrufen? Wie werden Sie Funktionsergebnisse für die nicht-leeren Funktionen verarbeiten? –

+0

Ich würde sie durch Iterieren durch den Container aufrufen und nacheinander die Funktion ausführen, auf die der Funktionszeiger zeigt. Ich bin mir nicht so sicher, ob das, was ich tun möchte, möglich ist. Für nicht-void-Funktionen würde ich einfach den Rückgabewert einem void-Zeiger zuweisen und versuchen, damit umzugehen (ist das überhaupt möglich?). –

+0

Warum die Funktionszeiger speichern? Warum speichern Sie nicht einfach einen Identifikator, mit dem Sie die auszuführende Funktion auswählen können? (ZB switch (FuncId) {case MULT: ... break;}) Wie auch immer, Sie benötigen eine Methode, um die gewählte Funktion sinnvoll anzuwenden (z. B. wo geht der Rückgabewert einer Funktion?) – MatthewToday

Antwort

1

Sie können nicht eine polymorphe Funktion in einer Klasse, da Funktionen setzen, die (oder zurück) nehmen verschiedene Dinge nicht auf die gleiche Art und Weise verwendet werden (mit derselben Schnittstelle), die etwas von Polymorphismus erforderlich ist.

Die Idee, eine Klasse von mit einer virtuellen Funktion für jede mögliche Funktion Art zu schaffen, Sie würden arbeiten müssen, aber seine Verwendung seltsam mir fühlt sich (ohne etwas über Ihr Problem zu wissen!): Welche Funktionen würden eine abgeleitete Klasse überschreiben ? Sind Ihre Funktionen nicht unkorreliert?

Wenn Ihre Funktionen nicht korreliert sind (wenn es keinen Grund gibt, sie als Mitglieder derselben Klasse zu gruppieren oder wenn sie statische Funktionen sind, da sie keine Membervariablen benötigen), sollten Sie sich für etwas anderes entscheiden. Wenn Sie Ihre Funktionen zufällig auswählen, könnten Sie einfach mehrere verschiedene Container haben, einen für den Funktionstyp, und dann einfach einen Container und dann eine Funktion auswählen.

Können Sie einige Beispiele für Ihre Funktionen erstellen?

+0

Ja einige Funktionen sind unkorreliert, aber nicht alle, zum Beispiel ist die Funktion zum Lösen von Polynomen ersten Grades grundsätzlich: addieren, subtrahieren, dividieren, multiplizieren, root, square und auch swap (zwei Variablen) und reverse (machen eine Zahl von positiv, negativ oder und umgekehrt). Bei komplexeren Problemen, wie Polynomen zweiten Grades oder Differentialen, muss ich jedoch Funktionen verwenden, die Werte vergleichen, Funktionen, die eine "Logik" oder einen einfachen Algorithmus haben, usw. Diese Funktionen benötigen möglicherweise eine Referenz oder eine Rückgabe von a Wert und sind somit völlig anders als der erste Satz. –

2

Eine typische Idee für virtuelle Maschinen ist es, einen separaten Stack zu haben, der für die Übergabe von Argumenten und Rückgabewerten verwendet wird.

Ihre Funktionen können immer noch vom Typ void fn (void) sein, aber das Argument wird manuell übergeben und zurückgegeben.

Sie können etwas tun:

class ArgumentStack { 
    public: 
     void push(double ret_val) { m_stack.push_back(ret_val); } 

     double pop() { 
      double arg = m_stack.back(); 
      m_stack.pop_back(); 
      return arg; 
     } 

    private: 
     std::vector<double> m_stack; 
}; 
ArgumentStack stack; 

... so eine Funktion könnte wie folgt aussehen:

// Multiplies two doubles on top of the stack. 
void multiply() { 
    // Read arguments. 
    double a1 = stack.pop(); 
    double a2 = stack.pop(); 

    // Multiply! 
    double result = a1 * a2; 

    // Return the result by putting it on the stack. 
    stack.push(result); 
} 

Dies kann auf diese Weise verwendet werden:

// Calculate 4 * 2. 
stack.push(4); 
stack.push(2); 
multiply(); 
printf("2 * 4 = %f\n", stack.pop()); 

Folgst du?

+0

Nein, nicht wirklich und es ist eine Schande, denn es scheint, als ob du etwas hier hast ... Hast du einen Link, den ich über Custom Stacks herausfinden kann? –

+0

Vielleicht können Sie versuchen, etwas weiter zu lernen. http://en.wikipedia.org/wiki/Forth_%28programming_language%29 Es verwendet den gleichen Ansatz, der auch Java VM inspiriert hat (wenn ich recht habe) Bitte fragen Sie erneut, wenn Sie weitere Hilfe benötigen. –

+0

@Alex möchten Sie vielleicht einen Blick auf http://en.wikipedia.org/wiki/Stack-oriented_programming_language – wich

1

Was Sie selbst erwähnt haben, kann wahrscheinlich durch einen Container std::function oder diskriminierte Union wie Boost::variant implementiert werden.
Zum Beispiel:

#include <functional> 
#include <cstdio> 
#include <iostream> 

struct F { 
    virtual ~F() {} 
}; 

template< class Return, class Param = void > 
struct Func : F { 
    std::function< Return(Param) > f; 
    Func(std::function< Return(Param) > const& f) : f(f) {} 
    Return operator()(Param const& x) const { return f(x); } 
}; 

template< class Return > 
struct Func< Return, void > : F { 
    std::function< Return() > f; 
    Func(std::function< Return() > const& f) : f(f) {} 
    Return operator()() const { return f(); } 
}; 

static void f_void_void(void) { puts("void"); } 
static int f_int_int(int x) { return x; } 

int main() 
{ 
    F *f[] = { 
    new Func<void>(f_void_void), 
    new Func< int, int >(f_int_int), 
    }; 

    for (F **a = f, **e = f + 2; a != e; ++ a) { 
    if  (auto p = dynamic_cast< Func<void>*  >(*a)) { 
     (*p)(); 
    } 
    else if (auto p = dynamic_cast< Func< int, int >* >(*a)) { 
     std::cout<< (*p)(1) <<'\n'; 
    } 
    } 
} 

Aber ich bin nicht sicher, ob das wirklich ist, was Sie wollen ...
Was denken Sie über Alf P. Steinbach Kommentar?

+0

Ich bin nicht so sicher, dass ich Ihren Code verstehe, aber es scheint, als ob das, was Sie programmiert haben, funktionieren könnte. Ich habe nicht viel darüber nachgedacht, was Steinbach kommentiert, und bin mir immer noch nicht ganz sicher. –