2010-10-22 5 views
0

Je tente de tirer parti des fermetures C++ 0x pour rendre le flux de contrôle entre un lexeur personnalisé et un analyseur plus simple. Sans fermeture, je l'arrangement suivant:Exemple de fermetures/lambdas C++ 0x

//-------- 
// lexer.h 
class Lexer { 
public: 
    struct Token { int type; QString lexeme; } 
    struct Callback { 
    virtual int processToken(const Token &token) = 0; 
    }; 
    Lexer(); 
    int tokenize(const QList<Token> &patterns, QTextStream &stream, 
       Callback *callback); 
}; 
//------------- 
// foo_parser.h 
class FooParser: public Lexer::Callback { 
    virtual int processToken(const Lexer::Token &token); 
    int process(QTextStream *fooStream); 
    // etc.. 
} 
//-------------- 
// foo_parser.cc 
int FooParser::processToken(const Lexer::Token &token) { 
    canonicalize(token); 
    processLine(); 
    return 0; 
} 
int FooParser::process(QTextStream *fooStream) { 
    Lexer lexer; 
    // *** Jumps to FooParser::processToken() above! *** 
    return lexer.tokenize(patterns_, fooStream, this); 
} 

Le principal problème que j'ai avec le code ci-dessus est que je n'aime pas le « saut » dans le flux de contrôle de la lexer.tokenize() pour la FooParser :: Fonction processToken().

J'espère que les fermetures permettront quelque chose comme ceci:

int FooParser::process(QTextStream *fooStream) { 
    Lexer lexer; 
    return lexer.tokenize(patterns_, fooStream, [&](const Lexer::Token &token) { 
    canonicalize(token); 
    processLine(); 
    return 0; 
    }); 
    // ... 
} 

Au moins pour moi, il est beaucoup plus clair que les méthodes FooParser sera appelée via lexer.tokenize().

Malheureusement, les seuls exemples que je l'ai vu avec C++ 0x fermetures aller quelque chose comme ceci:

int total = 0; 
std::for_each(vec.begin(), vec.end(), [&total](int x){total += x;}); 
printf("total = %d\n", total); 

Et pendant que je peux obtenir ce code d'exemple pour travailler, je suis incapable de comprendre comment pour écrire une fonction comme std :: for_each() qui prend un Functor/closure comme argument et l'invoque.

Ce qui veut dire, je ne sais pas comment écrire une classe Foo telle que je peux le faire:

// Does this need to be templated for the Functor? 
struct Foo { 
    void doStuff(... what goes here??????) { 
    myArg(); 
    } 
}; 

int someNumber = 1234; 
Foo foo; 
foo.doStuff([&]() { printf("someNumber = %d\n", someNumber); } 

Pour cet exemple, le résultat attendu serait someNumber = 1234

Pour référence, mon compilateur est gcc version 4.5.1.

Merci beaucoup.

Répondre

3

doStuff peut prendre un std::function:

void doStuff(std::function<void()> f) 
{ 
    f(); 
} 

L'utilisation d'un modèle est une autre option:

template <typename FunctionT> 
void doStuff(FunctionT f) 
{ 
    f(); 
} 

Le type réel de l'expression lambda est unique et sans précision.