2010-06-27 7 views
8

j'avais un coup d'œil à la documentation de la classe « Fonction » dans Boost, et a trébuché à travers ceci:syntaxe bizarre C++ repéré dans les paramètres modèle Boost

boost::function<float (int x, int y)> f; 

Je dois admettre que cette syntaxe est très déroutant pour moi. Comment cela peut-il être légal C++?

Y a-t-il un truc sous le capot? Cette syntaxe est-elle documentée quelque part?

+0

Veuillez poser une seule question par question - si vous avez deux questions à poser, soumettez deux questions distinctes. – bdonlan

+0

Vrai, désolé, je ne le ferai plus – Dinaiz

+0

Vous pouvez éditer votre question pour supprimer l'une des questions pour la diviser en une autre question - il est difficile de répondre comme ça parce que si quelqu'un ne connaît que la réponse à l'une de vos questions , ils seront réticents à soumettre une réponse. – bdonlan

Répondre

9

[Modifier] Ceci est une réponse à la question originale, non éditée de l'auteur qui était en fait deux questions.

Je dois admettre que cette syntaxe est fortement déroutant pour moi. Comment cela peut-il être légal C++? :) Yat-il un truc sous le capot? Cette syntaxe est-elle documentée quelque part?

Ceci est parfaitement légal et n'est en fait pas trop compliqué.

template <class T> 
class C 
{ 
public: 
    T* function_pointer; 
}; 

void fn(int x) 
{ 
    cout << x << endl; 
} 

int main(int argc, char** argv) 
{ 
    C<void (int x)> c; 
    c.function_pointer = &fn; 
    c.function_pointer(123); // outputs x 
} 

Il est fondamentalement la même chose que faire:

typedef void Function(int); 
C<Function> c; 

Ce type est non seulement applicable C++, il est tout aussi applicable dans C (le type réel C est paramétrées). Le modèle magique ici prend quelque chose comme la fonction typedef ici et étant capable de détecter les types de valeurs et d'arguments de retour. Expliquer que cela serait trop long ici et boost :: function utilise beaucoup de meta-templates de traits de fonction dans boost pour récupérer cette information. Si vous voulez vraiment passer du temps à apprendre cela, vous devriez essayer de comprendre l'implémentation de boost en commençant par boost :: function_traits dans Boost.Type Traits.

Cependant, je veux résoudre votre problème général. Je pense que vous essayez trop de simplifier quelques lignes de code parfaitement acceptable. Il n'y a rien de mal à passer les arguments de vos sous-classes de commande à travers leurs constructeurs de sous-classes paramétrés. Est-ce que ça vaut vraiment la peine d'essayer d'impliquer des typelists et de booster des solutions de type: function, augmentant ainsi les temps de compilation et la complexité du code, juste pour ça?

Si vous voulez réduire davantage, il suffit d'écrire une fonction Execute qui exécutera une sous-classe de commande et l'ajouter à la pile undo et ainsi de suite:

typedef boost::shared_ptr<Command> CommandPtr; 

void execute(const CommandPtr& cmd) 
{ 
    cmd->execute(); 
    // add command to undo stack or whatever else you want to do 
} 

// The client can simply write something like this: 
execute(CommandPtr(new CmdAdd(some_value)); 

Je pense vraiment que le compromis d'essayer pour le rendre plus compliqué ne vaut pas la peine. Les auteurs de boost voulaient écrire une solution extrêmement générale pour boost :: function qui serait utilisée par de nombreuses personnes sur de nombreuses plateformes et compilateurs. Cependant, ils n'ont pas essayé de généraliser un système de commande capable d'exécuter des fonctions avec des signatures différentes à travers un système d'annulation unifié (nécessitant ainsi que l'état de ces commandes soit préservé même après avoir fini de les appeler et être capable d'annuler et re -exécute-les sans spécifier à nouveau les données d'état d'origine sur les exécutions suivantes). Pour cela, votre approche basée sur l'héritage est probablement la meilleure et la plus directe.

+2

'typedef float (int, int) Command', je suis désolé de le dire, n'est pas légal C. Le code C correct serait' typedef float Command (int, int) '. 'typedef' prend une déclaration régulière, et au lieu de définir l'objet nommé (ie, fonction ou variable), il utilise le nom comme alias pour le type de type de l'objet. –

+0

+1 Grande réponse – fingerprint211b

+0

@Dale Excuses, vous avez raison et c'est aussi illégal en C++. C'était une erreur hâtive quand on essayait d'expliquer à quoi C était paramétré avec C c; C'est l'équivalent de l'écriture: typedef float Command (int, int); C c. Je l'ai édité pour corriger l'erreur. – stinky472