2009-03-13 5 views
2

Je cherche une macro facile à utiliser pour appeler une fonction seulement une fois pour une valeur spécifique. Par exemple:Comment appeler une fonction seulement une fois par valeur en C++?

void foo(Object* obj) 
{ 
    // Print out the name of each object only once 
    DO_ONCE(obj, printf("This gets printed only once per object! %s\n",obj->GetName())); 
} 

Puis

Object obj1("obj1Name"),obj2("obj2Name"); 
foo(&obj1); 
foo(&obj1); 
foo(&obj2); 

Si imprimer

This gets printed only once per object! obj1Name 
This gets printed only once per object! obj2Name 

Répondre

3

Mettez vos objets dans un récipient et filtre/groupe pour que chacun n'apparaît une fois. Cela peut être fait trivialement en utilisant set (ou std::tr1::unordered_set) comme le conteneur de vos objets. Cela les rend effectivement uniques. Vous pouvez ensuite itérer sur le conteneur.

Ou, comme d'autres l'ont proposé, d'utiliser le conteneur à l'intérieur de la fonction comme un dispositif de mémoisation. Cependant, en général, je pense que le regroupement explicite des résultats pourrait être plus approprié.

2

Je préfère une carte

void foo(Object* obj){ 
    // Print out the name of each object only once 
    static std::map<Object*, size_t> calls; 
    if(calls[obj] == 0) { 
     std::cout << "This gets printed only once per object! " 
        << obj->GetName(); 
     calls[obj] = 1; 
    } 
} 

Vous pouvez également décider d'incrémenter le compteur si vous voulez compter les appels aussi. Mais notez que ce n'est pas vraiment sûr. Si vous supprimez un objet, puis le relancez et qu'il arrive à obtenir la même adresse, il sera supposé être déjà imprimé.

1
#include <iostream> 
#include <ostream> 
#include <set> 
#include <string> 

class Object 
{ 
public: 
    Object(const std::string& name): 
     name_(name) 
    {} 
    std::string GetName() const 
    { 
     return name_; 
    } 
private: 
    std::string name_; 
}; 

void print(Object* object) 
{ 
    std::cout << object->GetName() << std::endl; 
} 

template <typename T, typename TFunction> 
void doOnce(T* object, TFunction function) 
{ 
    static std::set<T*> objectsThatWasThere; 

    if (objectsThatWasThere.end() == objectsThatWasThere.find(object)) 
    { 
     function(object); 
     objectsThatWasThere.insert(object); 
    } 
} 

int main() 
{ 
    Object obj1("Test"); 
    Object obj2("The"); 

    doOnce(&obj1, print); 
    doOnce(&obj1, print); 
    doOnce(&obj1, print); 
    doOnce(&obj2, print); 
    doOnce(&obj2, print); 
    doOnce(&obj2, print); 

    return 0; 
} 
1

Vous aurez probablement besoin de mémoriser les objets. Quelque chose linke

bool do_once(Object * obj) 
{ 
    static std::set<Object*> memo; 
    if (memo.count(obj)) 
    { 
     memo.insert(obj); 
     return true; 
    } 
    return false; 
} 
#define DO_ONCE(o,a) (do_once(obj) && a) 
1
#include <set> 

... 

#define DO_ONCE(type, val, stmt) \ 
do \ 
{ \ 
    type __tmp = (val); \ 
    static std::set <type> __memo; \ 
    if (__memo.find(__tmp) == __memo.end()) \ 
    { \ 
     __memo.insert(__tmp); \ 
     do { stmt; } while(0); \ 
    } \ 
} \ 
while(0) 

... 

DO_ONCE(Object *, obj, printf(...)); 
+0

Cela ne fonctionnera pas, une nouvelle série std :: <> est créé pour chaque invocation de la macro. – Ismael

+0

Maintenant, ce n'est pas --- c'est déclaré statique! –

+0

Eh bien oui ... pour chaque INVOCATION dans le code, mais n'est-ce pas exactement ce qui est nécessaire? Si vous avez plusieurs routines, vous voulez appeler chacune d'entre elles une fois. –

0

Concept:

template<class t1> void do_once(t1* obj) { 
    static std::map<t1*,bool> was_here; 
    if (was_here[obj]==false) was_here[obj]=true, throw obj; 
} 

void ff(int * x) 
{ 
    try {do_once(x); } catch (int* obj) { printf("First time: %d\n",*obj);} 
} 
Questions connexes