Kann es eine Funktion ExecProcedure(string name) geben?



  • Hi,
    da du ja selber lernen willst, gebe ich dir google-stichwörter, mit denen du dir die Syntax recht schnell erklären kannst:

    c++Beginner schrieb:

    Was heißt typedef?
    Wieso setzt du einen Funktionsnamen in Klamern und mit einem Stern davor:

    Google: Funktionspointer / Funktionszeiger

    Wieso übergibst du den String als Referenz, er soll doch nicht verändert werden??

    Ich übergebe ihn als konstante Referenz. Er soll nicht verändert werden, dafür ist das const da, er soll aber auch nicht kopiert werden (um Laufzeit zu sparen), dafür ist es eine Referenz.
    Google: const correctness

    Ich habe schon mal etwas von Maps gehört, aber ich weiß nicht, was du da mit der Map genau machst.

    Die map besteht aus den Key -> Value paaren
    string -> funktion
    mit
    std::map<T, U>::insert
    fügst du ein neues paar hinzu. Das erklärt dann auch, was make_pair macht 😉

    Bei dieser Lösung kommst du ohne switch-Konstrukt aus (das übrigens in deinem Code *falsch* ist).

    Wieso ist mein switch-Konstrukt falsch?

    Weil man nur Integrale Werte (int, long, enum) in einem Switch-Konstrukt vergleichen kann, du vergleichst aber String-Literale:

    case "xyz": // sollte einen Fehler erzeugen
        xyz()
        break;
    

    wo hängt es denn bei exec_procedure?
    Google hints: STL iterator, function pointer (siehe oben), std::map find (in der Referenz deiner Wahl, z.b. cppreference.com oder cplusplus.com)

    Wenn du kein (gutes) C++ (Einsteiger) Buch hast, ist es drigend an der Zeit, dir eins zuzulegen 😉

    - Edit: zu langsam -



  • case "xyz": // sollte einen Fehler erzeugen
        xyz() // sollte auch einen Fehler erzeugen ;) Flüchtigkeitsfehler
        break;
    

    Das heißt, immer wenn ich Strings mit festgelegten Werten vergleichen will, muss ich in if/else if/else-Konstrukt verwenden? Das ist aber blöd, gibt es da keine einfachere Lösung?

    Wenn du kein (gutes) C++ (Einsteiger) Buch hast, ist es drigend an der Zeit, dir eins zuzulegen 😉

    Ich hielt die durchgearbeiteten Bücher für gut 😉 Über Maps stand da auch was, was es ist, wusste ich auch noch, aber die einzelnen Funktionen dazu nicht.

    "Funktionszeiger" wurden gar nicht erwähnt, nur Pointer auf Objekte und Variablen.

    Danke für die Hilfe! Hätte auf keinen Fall gedacht, dass sowas geht.



  • Oh,

    ich habe gar nicht gesehen, dass in euren Funktionen die aufzurufenden Prozeduren bekannt sein müssen. Angenommen, sie sind nicht bekannt - fragt mich jetzt nicht wofür das gut ist - aber gibt es da auch eine Lösung?



  • Zu deiner switch-Frage: Nein, if ist da wohl erste Wahl.

    Zu deinem zweiten Post: Wie willst du etwas aufrufen, von dem du nicht weißt wie es heißt und wo es sich befindet? 😉

    Womöglich geht es mit plattformspezifischen Mittelchen (ich denke da an DLLs), aber mit Standardmitteln wohl nicht.



  • c++Beginner schrieb:

    Oh,

    ich habe gar nicht gesehen, dass in euren Funktionen die aufzurufenden Prozeduren bekannt sein müssen. Angenommen, sie sind nicht bekannt - fragt mich jetzt nicht wofür das gut ist - aber gibt es da auch eine Lösung?

    Was soll eine unbekannte Funktion Deiner Meinung nach denn tun ?

    Gruß,

    Simon2.



  • Sagen wir es so: Es ist möglich, aber wenn die Funktion bzw der SPeicher nicht existiert bzw nicht belegt ist, hast du ein Problem (:

    Das meinte ich mit der heiklen Angelegenheit.



  • Was soll eine unbekannte Funktion Deiner Meinung nach denn tun ?

    Keine unbbekante Funktion. Ich meinte, dass ich einmal eine Methode "ExecProcedure" definieren muss und mich dann aber nicht darum kümmern muss, jedes Mal einen neuen Eintrag in der Map zu erzeugen, wenn eine Funktion hinzukommt - dann ist die switch-Variante meistens sogar kürzer.



  • c++Beginner schrieb:

    Was soll eine unbekannte Funktion Deiner Meinung nach denn tun ?

    Keine unbbekante Funktion. Ich meinte, dass ich einmal eine Methode "ExecProcedure" definieren muss und mich dann aber nicht darum kümmern muss, jedes Mal einen neuen Eintrag in der Map zu erzeugen, wenn eine Funktion hinzukommt - dann ist die switch-Variante meistens sogar kürzer.

    Du musst die Funktionen die du verwendest auch bekannt machen. Sei es nun das du jedesmal den Code deiner ExecProcedure um einen neuen if/else-Fall erweiterst oder einen neuen Eintrag in eine map einfügst. Ohne geht es nicht (Eine Funktion hat keine Namen in dem Sinne, das dieser zur Laufzeit noch bekannt wäre).

    Irgendwie musst du also deinen Code anpassen.

    Das sauberste ist aber tatsächlich die Lösung mit der map.

    cu André



  • c++Beginner schrieb:

    Was soll eine unbekannte Funktion Deiner Meinung nach denn tun ?

    Keine unbbekante Funktion. Ich meinte, dass ich einmal eine Methode "ExecProcedure" definieren muss und mich dann aber nicht darum kümmern muss, jedes Mal einen neuen Eintrag in der Map zu erzeugen, wenn eine Funktion hinzukommt - dann ist die switch-Variante meistens sogar kürzer.

    nö, ist sie nicht, da du ja strings vergleichen musst, hast du nicht mal ne switch-Anweisung:

    bool ExecProcedure(const std::string& str)
    {
        if(str == "hallo") {  // zeile 1
            hallo();          // zeile 2
            return true;      // zeile 3
        }                     // zeile 4
        else if(str == "answer") {
            answer();
            return true;
        }
        else
            return false;   
    }
    

    das sind jeweils 4-5 Zeilen, wenn es ordentlich eingerückt und übersichtlich sein soll.

    Die Map-Variante benötigt nur 1 Zeile:

    functions.insert( make_pair("answer", &answer) );
    

    und gerade wenn die Funktionsanzahl 10+ erreicht, tut Beispiel 1 schon in den Augen weh. Und hinzufügen musst du die Funktionen so oder so!

    - Edit: zu langsam -



  • Auch ordentlich:

    bool ExecProcedure(const std::string& str)
    {
        if(str == "hallo")    // zeile 1
            hallo();          // zeile 2
        else if(str == "answer")
            answer();
        else
            return false;  
        return true;
    }
    


  • So, ich habe mal etwas ausprobiert, obwohl ich kein Fan von globalen Variablen bin. Ich übernehme für den Code auch keine Garantien:

    Ziel des Codes ist es, mit möglichst wenig gegenseitigen Wissen Funkionen über einen Namen aufzurufen:

    // main.cpp

    #include "exec_fn.h"
    
    int main()
    {
      exec::ExecuteFunction("ShowA");
      exec::ExecuteFunction("ShowB");
      exec::ExecuteFunction("ShowA");
      exec::ExecuteFunction("wait");
    }
    

    // exec_fn.h

    #if !defined(EXEC_FN_HEADER)
    #define EXEC_FN_HEADER
    
    #include <string>
    
    namespace exec
    {
      typedef void (*function_type)(); 
    
      void Register(const std::string& functionName, function_type function);
      void ExecuteFunction(const std::string& functionName);
      class RegisterFunction
      {
        public:
          RegisterFunction(const std::string& functionName, function_type function)
          {
            Register(functionName, function);
          }
      };
    }
    
    #endif
    

    // exec_fn.cpp

    #include "exec_fn.h"
    #include <map>
    
    namespace exec
    {
      std::map<std::string, function_type>& GetFunctionMap()
      {
        static std::map<std::string, function_type> functionMap;
        return functionMap;
      }
    
      void Register(const std::string& functionName, function_type function)
      {
        std::map<std::string, function_type>& functionMap = GetFunctionMap();
        if(functionMap.find(functionName) == functionMap.end())
          functionMap[functionName] = function;
      }
    
      void ExecuteFunction(const std::string& functionName)
      {
        std::map<std::string, function_type>& functionMap = GetFunctionMap();
        std::map<std::string, function_type>::iterator pos = functionMap.find(functionName);
        if(pos != functionMap.end())
          (pos->second)();
      }
    }
    

    Zudem noch 3 weitere Dateien die aber alle den gleichen Aufbau haben (Eine void-Funktion ohne Parameter, eine globale Variable...). Ich zeige hier nur die Implementierung von der wait.h/wait.cpp.

    // wait.h

    #if !defined(WAIT_HEADER)
    #define WAIT_HEADER
    void wait();
    #endif
    

    // wait.cpp

    #include "exec_fn.h"
    #include <iostream>
    
    void wait()
    {
      std::cin.clear();
      std::cin.ignore(std::cin.rdbuf()->in_avail());
      std::cin.get();
    }
    
    // Hiermit wird die wait-Funktion registriert
    exec::RegisterFunction wait_("wait", &wait);
    

    Die restlichen Header/Sourcen kann man sich wohl selbst ausdenken...

    Ob man dies als Sauber bezeichnen kann wage ich aber zu bezweifeln (Getestet unter VC++ 2005).

    cu André



  • c++Beginner schrieb:

    Was soll eine unbekannte Funktion Deiner Meinung nach denn tun ?

    Keine unbbekante Funktion. Ich meinte, dass ich einmal eine Methode "ExecProcedure" definieren muss und mich dann aber nicht darum kümmern muss, jedes Mal einen neuen Eintrag in der Map zu erzeugen, wenn eine Funktion hinzukommt ..

    Ach so: Du möchtest also eine "automatische Externalisierung", sobald Du eine Funktion hinzufügst.

    Ich weiß gar nicht, ob mir das erstrebenswert erschiene .... aber da der Compiler das nicht kann, geht's halt auch nicht.

    Gruß,

    Simon2.


Anmelden zum Antworten