C ++: Fonction wrapper qui se comporte comme la fonction elle-même
Comment puis-je écrire un wrapper qui peuvent envelopper toute fonction et peut être appelé comme la fonction elle-même?
La raison que j'ai besoin de ceci: je veux un objet Timer qui peuvent encapsuler une fonction et se comportent exactement comme la fonction elle-même, plus il enregistre le temps cumulé de l'ensemble de ses appels.
Le scénario devrait ressembler à ceci:
//a function whose runtime should be logged
double foo(int x) {
//do something that takes some time ...
}
Timer timed_foo(&foo); //timed_foo is a wrapping fct obj
double a = timed_foo(3);
double b = timed_foo(2);
double c = timed_foo(5);
std::cout << "Elapsed: " << timed_foo.GetElapsedTime();
Comment puis-je écrire ce Timer
classe?
Je suis en train d'essayer quelque chose comme ceci:
#include <tr1/functional>
using std::tr1::function;
template<class Function>
class Timer {
public:
Timer(Function& fct)
: fct_(fct) {}
??? operator()(???){
//call the fct_,
//measure runtime and add to elapsed_time_
}
long GetElapsedTime() { return elapsed_time_; }
private:
Function& fct_;
long elapsed_time_;
};
int main(int argc, char** argv){
typedef function<double(int)> MyFct;
MyFct fct = &foo;
Timer<MyFct> timed_foo(fct);
double a = timed_foo(3);
double b = timed_foo(2);
double c = timed_foo(5);
std::cout << "Elapsed: " << timed_foo.GetElapsedTime();
}
(BTW, je sais de gprof
et d'autres outils pour le profilage de l'exécution, mais avoir un tel Timer
objet pour le journal de l'exécution d'une sélection de fonctions est plus pratique pour mes fins.)
source d'informationauteur Frank
Vous devez vous connecter pour publier un commentaire.
Voici un facile façon à envelopper les fonctions.
Fondamentalement, ce que vous voulez faire est impossible dans le courant de C++. Pour un certain nombre d'arité de la fonction que vous souhaitez envelopper, vous avez besoin de surcharger par
Mais alors c'est pas encore parfaitement forwarding (certains cas limites sont toujours là), mais il devrait fonctionner raisonnable. Si vous vous limitez à const références, vous pouvez aller avec celui-ci (pas testé):
Noter que pour le type de retour, vous pouvez utiliser du coup de pouce des types de fonction de bibliothèque. Puis
Vous pouvez aussi surcharger l'aide de la pure valeur des paramètres, et puis si vous voulez passer quelque chose par référence, utilisez
boost::ref
. C'est en fait une jolie commune de la technique, en particulier lorsque ces paramètres sont sauvegardés (cette technique est également utilisée pourboost::bind
):Ou vous pouvez aller et ajouter les surcharges pour les deux const et non const versions comme expliqué ci-dessus. Regarder dans Coup de pouce.Préprocesseur pour savoir comment écrire le bon macros.
Vous devez être conscient que tout cela va devenir plus difficile si vous voulez être en mesure de passer arbitraire callables (pas seulement des fonctions), car vous aurez besoin d'un moyen d'obtenir ensuite leur type de résultat (qui n'est pas du tout facile). C++1x, fera de ce genre de choses beaucoup plus facile.
Je suppose que vous en avez besoin pour des fins de test et ne vont pas à l'utiliser comme un véritable procurations ou des décorateurs. Donc vous n'aurez pas besoin d'utiliser l'opérateur() et peut utiliser n'importe quel autre plus-moins pratique la méthode de l'appel.
Afin de tester certains de la vôtre fonction, vous devez utiliser uniquement
test_time
fonction et non pas le directTimerWrapper
structureStroustrup a démontré une fonction wrapper(injaction) compétence avec la surcharge de l'
operator->
. L'idée clé est:operator->
sera repeatly appelé jusqu'à ce qu'il rencontre un natif de type pointeur, alors laissez -Timer::operator->
retour un temp de l'objet, et la temp de l'objet de retour de son pointeur. Alors la suite va se passer:Et vous pouvez injecter le code dans le ctor et la dtor. Comme cette.
La mise en œuvre et l'utilisation sont à la fois faciles.
Une solution à l'aide des macros et des modèles: Par exemple, vous souhaitez envelopper
Avant et après l'appel de foo() les fonctions wrapper beginWrap() et endWrap() doit être appelée. (Avec endWrap() étant une fonction de modèle.)
La macro
utilise la préséance de la virgule-opérateur pour assurer beginWrap() est appelée en premier. Le résultat de f est passé à endWrap() qui renvoie simplement.
Donc la sortie est:
Et le résultat r contient 10.1.
Vous vous absentez pour un grand défi si vous cherchez à créer une classe générique qui peut s'enrouler et appel d'une fonction arbitraire. Dans ce cas, vous auriez à faire le foncteur (l'opérateur()) retour double et de prendre un int en paramètre. Ensuite, vous avez créé une famille de classes que l'on peut appeler toutes les fonctions avec la même signature. Dès que vous voulez ajouter d'autres types de fonctions, vous avez besoin de plus foncteurs de cette signature, par exemple
EDIT: Quelques fautes d'orthographe
Ce n'est pas vraiment clair pour moi que ce que vous êtes à la recherche.. Cependant, pour l'exemple donné, il est tout simplement:
Note: Ceci permettra de mesurer le temps en secondes. Si vous voulez avoir une haute précision des chronomètres, vous avez probablement à vérifier les OS des fonctionnalités spécifiques (comme GetTickCount ou QueryPerformanceCounter sur Windows).
Si vous voulez avoir une fonction générique wrapper, vous devriez avoir un regard sur Coup de pouce.Lier qui aidera tremendeously.
Si votre compilateur prend en charge variadic macros, je voudrais essayer ceci:
Donc, pour l'utiliser, vous devrez faire cela:
Large que le brassard, et vous auriez besoin de jouer pour obtenir des types de retour au travail (je pense que tu aurais à ajouter un nom de type à la TIME_MACRO appel et puis de générer une variable temp).
Vous pouvez probablement trouver une réponse si vous regardez à la mise en œuvre de std::tr1::fonction qui vous comprennent.
En c++11, std:: function est mis en œuvre avec variadic templates. L'utilisation de tels modèles votre classe timer peut ressembler à
Voici comment je le ferais, à l'aide d'un pointeur de fonction au lieu d'un modèle:
Je l'ai changé pour ne pas prendre une référence à la fonction, mais juste un simple pointeur de fonction. L'utilisation reste la même:
Dans les fonctions C++ sont des citoyens à part entière, vous pouvez littéralement passer une fonction comme une valeur.
Puisque vous voulez prendre un int et un retour double: