2013-05-26 8 views
6

Ho scritto un parser di espressioni di base e mi piacerebbe che fosse estensibile in modo da poter analizzare i tipi di espressione definiti dall'utente. Ad esempio, se durante l'analisi ho incontrato il carattere <, voglio creare un'istanza della classe utilizzata per analizzare le espressioni che iniziano con questo carattere.Mappa C++ <char, puntatore metodo statico>?

Ho due domande:

  1. Come posso associare un personaggio a un puntatore metodo statico?

    Desidero utilizzare un metodo statico che restituirà una nuova istanza della classe poiché non è possibile ottenere un puntatore al costrutto della classe. La seguente sintassi è probabilmente sbagliato, ma questa è l'idea:

    typedef static IValue * (*returnPtrIValue)(); 
    map<char, returnPtrIValue> ... 
    
  2. Supponendo che ho di classe A e di classe B estende la classe A, posso inizializzare un puntatore a una funzione che restituisce un puntatore/ref a un A con un puntatore a una funzione che restituisce un puntatore/ref a un B poiché una B è una A?

    Per esempio, posso fare:

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

L'analisi viene eseguita da un metodo/funzione 'class' condiviso da tutti gli oggetti, quindi perché si desidera creare una nuova istanza di una classe ogni volta? Basta memorizzare un oggetto globale della classe associato a '<' e usare il suo metodo. – iammilind

+0

Perché nel modo in cui ho progettato il mio parser, un'espressione è un oggetto che si analizza da un pezzo di corda. – Virus721

+0

se sei interessato a scrivere un parsing/lexer ti suggerisco di dare un'occhiata a 'libclang', ad esempio http://stackoverflow.com/questions/14509120/any-tutorial-on-libclang – user2384250

risposta

2

1) basta rimuovere static dal typedef, un "metodo statico" è come una semplice funzione (dichiarata solo all'interno del campo di applicazione di un classe).

2) che sembrava legittimo ma purtroppo ottengo un errore di compilazione:

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

Sembra che function pointers don't support covariant return types ...

+0

Grazie, vedrò se posso farlo in un altro modo – Virus721

0

Questo codice dovrebbe rispondere alle vostre domande, anche se non esattamente . In effetti, ho risolto alcuni dei tuoi problemi utilizzando le chiamate virtual (fai attenzione ai problemi di prestazioni).

#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; 

} 

prega di notare che non mi piace questo disegno per un parser. In qualche modo imita la riflessione Java ed è destinata ad avere problemi di prestazioni. Vedi se riesci a perfezionarlo.

+0

Grazie, vedrò se riesco ad adattarlo a quello che sto facendo. – Virus721

+0

Si noti che utilizza alcune funzionalità C++ 11 non vitali. Può essere opportunamente declassato. – gd1

3

1: Rimuovere static dal typedef, come:

typedef IValue * (*returnPtrIValue)(); 

puntatore a funzione membro statica può essere poi assegnato alla variabile (o essere messo in mappa) dello stesso tipo, come:

returnPtrIValue fun = &SomeClass::somestaticfun; 

È questo che stai chiedendo?

2: in generale - n. Non nel modo typesafe, almeno. Covariance non funziona in C++ in questo modo.

Se davvero vuole fare questo si può fare questo è sia con reinterpret_cast o fare qualche aggiustamenti con i sindacati, ma questo può essere compilatore-dipendente e non vorrei raccomandare che (mi può dare qualche suggerimento se lo vuoi comunque).

UPDATE:Here is the really good article, che spiega come implementare i delegati in C++ con l'aiuto dei puntatori di funzione (membro) in C++. Scava molto in profondità nella domanda e ho scoperto che la prima metà di esso è un buon riferimento/spiegazione dei puntatori di funzione (membro) in C++ e come lavorare con essi. Suggerisco di verificarlo se sei interessato a capire come funzionano in C++.

+0

Grazie, per 1 sì è quello che mi serviva, e per il 2 vedrò se c'è un altro modo. – Virus721

+0

@ Virus721 Cool, commenta qui se hai bisogno di suggerimenti su 2. Controlla anche l'aggiornamento sul mio post - potrebbe diventare utile per te. –

+0

Grazie, ma ho trovato quello che mi serviva qui: http://stackoverflow.com/questions/4007382/how-to-create-class-objects-dynamically: D – Virus721

1

Se stai usando C++ 11, si può provare qualcosa di simile:

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

In questo modo non è necessario avere alcuna metodi statici.

+0

Grazie, sembra elegante, ma lo userò su mobile dispositivi che utilizzano Visual Studio 2005 e non sono sicuro che gestisca roba C++ 11. – Virus721

+0

Sì, avrai almeno vs2010. – catscradle

Problemi correlati