2013-05-26 4 views
6

Ich habe einen sehr einfachen Ausdrucksparser geschrieben und möchte, dass er erweiterbar ist, damit er benutzerdefinierte Ausdruckstypen parsen kann. Zum Beispiel, wenn ich beim Parsen das Zeichen < treffe, möchte ich eine Instanz der Klasse erstellen, die zum Parsen von Ausdrücken verwendet wird, die mit diesem Zeichen beginnen.C++ - Map <Zeichen, statischer Methodenzeiger>?

Ich habe zwei Fragen:

  1. Wie kann ich ein Zeichen zu einem statischen Methode Zeiger verknüpfen?

    Ich möchte eine statische Methode verwenden, die eine neue Instanz der Klasse zurückgibt, da ich keinen Zeiger auf die Klasse Constructr erhalten kann. Die folgende Syntax ist wahrscheinlich falsch, aber das ist die Idee:

    typedef static IValue * (*returnPtrIValue)(); 
    map<char, returnPtrIValue> ... 
    
  2. Angenommen, ich Klasse A, und die Klasse B erstreckt Klasse A, kann ich einen Zeiger auf eine Funktion, die einen Zeiger/ref an einem A initialisieren mit ein Zeiger auf eine Funktion, die einen Zeiger/ref auf ein B zurückgibt, da ein B ein A ist?

    Zum Beispiel kann ich tun:

    typedef A * (*returnPtrA)(); 
    B * func() { ... } 
    returnPtrA foo = func; 
    
+0

Das Parsen wird durch eine 'class' Methode/Funktion durchgeführt, die über alle Objekte verteilt wird. Warum möchten Sie dann jedes Mal eine neue Instanz einer Klasse erstellen? Speichern Sie einfach ein globales Objekt der Klasse, die mit '<' verknüpft ist, und verwenden Sie deren Methode. – iammilind

+0

Da ein Ausdruck in der Weise, wie ich meinen Parser entworfen habe, ein Objekt ist, das sich selbst aus einer Zeichenfolge heraus analysiert. – Virus721

+0

Wenn Sie ein Parsing/Lexer schreiben möchten, schlage ich vor, 'libclang' zu betrachten, zum Beispiel http://stackoverflow.com/questions/14509120/any-tutorial-on-libclang – user2384250

Antwort

2

1) Nur static von Ihrem typedef entfernen, eine „statische Methode“ ist wie eine einfache Funktion (nur in dem Umfang des einer erklärten Klasse).

2) die legit schien aber leider bekomme ich einen Compiler-Fehler:

error: invalid conversion from 'B* (*)()' to 'A* (*)()' 

Es scheint, dass function pointers don't support covariant return types ...

+0

Danke, ich werde sehen wenn ich es anders machen kann. – Virus721

0

Dieser Code sollte Ihre Fragen beantworten, auch wenn nicht genau . In der Tat habe ich einige Ihrer Probleme gelöst, indem Sie virtual Aufrufe (Vorsicht: Leistungsprobleme).

#include <iostream> 
#include <map> 


struct parse_result { 
    // something here 
}; 

class parser { 
public: 
    virtual parse_result parse() = 0; 
}; 

class parser1 : public parser { 
public: 
    parse_result parse() { 
     // something here 
     std::cout << "Called parser1::parse()" << std::endl; 
     return parse_result(); 
    } 
}; 

class parser2 : public parser { 
public: 
    parse_result parse() { 
     // something here 
     std::cout << "Called parser2::parse()" << std::endl; 
     return parse_result(); 
    } 
}; 

static parser1* make_parser1() { 
    return new parser1(); 
} 

static parser2* make_parser2() { 
    return new parser2(); 
} 

typedef parser* (*parser_factory_method)(); 


int main() { 

    std::map<char, parser_factory_method> parsers; 
    parsers.insert(std::make_pair('1', (parser_factory_method) make_parser1)); 
    parsers.insert(std::make_pair('2', (parser_factory_method) make_parser2)); 

    for (auto entry : parsers) { 
     std::cout << "Calling parser for " << entry.first << std::endl; 
     parser_factory_method pfm = entry.second; 
     parser* p = pfm(); 
     p->parse(); // parse_result is ignored here, but can be used as needed 
     delete p; 
    } 

    return 0; 

} 

Bitte beachten Sie, dass Ich mag diesen Entwurf nicht für einen Parser. Es imitiert Java-Reflektion irgendwie und es ist zu Leistungsproblemen verdammt. Sehen Sie, ob Sie es verfeinern können.

+0

Danke, ich werde sehen, ob ich das anpassen kann, was ich mache. – Virus721

+0

Bitte beachten Sie, dass es einige unwichtige C++ 11 Funktionalitäten verwendet. Es kann bequem heruntergestuft werden. – gd1

3

1: Entfernen static von Ihrem typedef, wie:

typedef IValue * (*returnPtrIValue)(); 

Zeiger auf statische Member-Funktion kann dann der Variablen zugewiesen werden (oder in der Karte gesetzt werden) dieser Art, wie:

returnPtrIValue fun = &SomeClass::somestaticfun; 

Ist es das, wonach Sie fragen?

2: Allgemein gesprochen - nein. Zumindest nicht auf typsichere Weise. Covariance funktioniert in C++ nicht so.

Wenn Sie wirklich dies tun wollen, können Sie dies entweder mit reinterpret_cast ist oder einige Hacks mit den Gewerkschaften zu tun, aber dies kann Compiler-abhängig sein, und ich würde das nicht empfehlen (ich kann Ihnen einige Hinweise geben, wenn Du willst das trotzdem).

UPDATE:Here is the really good article, das erläutert, wie Delegaten in C++ mit Hilfe (Element) Funktionszeiger in C++ implementiert werden. Es taucht ziemlich tief in die Frage ein und ich habe herausgefunden, dass die erste Hälfte davon ziemlich gute Referenz/Erklärung von (Mitglieds-) Funktionszeigern in C++ ist und wie man mit ihnen arbeitet. Ich schlage vor, es zu überprüfen, wenn Sie daran interessiert sind zu verstehen, wie sie in C++ arbeiten.

+0

Danke, für 1 ja, das ist was ich brauchte, und für die 2 werde ich sehen, ob es einen anderen Weg gibt. – Virus721

+0

@ Virus721 Cool, kommentieren Sie hier, wenn Sie Tipps zu 2 brauchen. Auch überprüfen Sie update auf meinem Post - könnte für Sie nützlich sein. –

+0

Danke, aber ich habe gefunden, was ich hier gebraucht habe: http://StackOverflow.com/Questions/4007382/How-to-Create-Class-Objects-dynamically: D – Virus721

1

Wenn Sie C++ 11 verwenden, können Sie so etwas wie dies versuchen:

#include <map> 
#include <functional> 
... 
std::map<char, std::function<parser*()>> m; 
m['a'] = []{return new parser_for_a;}; 

Auf diese Weise brauchen Sie keine statischen Methoden haben.

+0

Danke, scheint elegant, aber ich werde das auf dem Handy verwenden Geräte mit Visual Studio 2005 und ich bin mir nicht sicher, ob es C++ 11 Sachen handhabt. – Virus721

+0

Yeah, du wirst VS2010 zumindest brauchen. – catscradle

Verwandte Themen