2017-10-09 8 views
0

J'ai essayé de trouver un moyen pour que ma méthode de classe prenne un nombre arbitraire de fonctions de rappel, les exécute toutes, puis stocke la sortie. Je pense que cela fonctionne, mais y a-t-il un moyen de le faire où je ne dois pas obliger l'utilisateur à intégrer toutes les fonctions de rappel dans un vecteur? Cela aussi se sent mal. N'hésitez pas à mentionner d'autres choses qui ne sont pas idéales.C++ méthode de classe qui prend un nombre arbitraire de callbacks et stocke les résultats

#include <iostream> 
#include <functional> 
#include <vector> 

class MyObj{ 
public: 
    // where I store stuff 
    std::vector<double> myResults; 

    // function that is called intermittently 
    void runFuncs(const std::vector<std::function<double()> >& fs){ 
     if (myResults.size() == 0){ 
      for(auto& f : fs){ 
       myResults.push_back(f()); 
      } 
     }else{ 
      int i (0); 
      for(auto& f : fs){ 
       myResults[i] = f(); 
       i++; 
      } 
     } 
    } 

}; 


int main(int argc, char **argv) 
{ 

    auto lambda1 = [](){ return 1.0;}; 
    auto lambda2 = [](){ return 2.0;}; 

    MyObj myThing; 

    std::vector<std::function<double()> > funcs; 
    funcs.push_back(lambda1); 
    funcs.push_back(lambda2); 
    myThing.runFuncs(funcs); 

    std::cout << myThing.myResults[0] << "\n"; 
    std::cout << myThing.myResults[1] << "\n"; 

    std::vector<std::function<double()> > funcs2; 
    funcs2.push_back(lambda2); 
    funcs2.push_back(lambda1); 
    myThing.runFuncs(funcs2); 

    std::cout << myThing.myResults[0] << "\n"; 
    std::cout << myThing.myResults[1] << "\n"; 


    return 0; 
} 
+0

Que faut-il si 'runFuncs' est appelé deux fois, en passant plus rappels la deuxième fois que le premier? À l'heure actuelle, votre programme présente un comportement indéfini dans ce cas. –

+0

J'utiliser '.empty()' pour décider si le vecteur était vide ou non, mais je pense qu'il vaudrait mieux le redimensionner au nombre de callbacks puis assigner les résultats dans une boucle for. Il n'y a aucune garantie que je vois que si le vecteur n'est pas vide, c'est la bonne taille. –

+1

Cela me semble un peu plus propre. * hausser les épaules * https://ideone.com/WN697O –

Répondre

1

Quelque chose comme ça, peut-être:

template <typename... Fs> 
void runFuncs(Fs... fs) { 
    myResults = std::vector<double>({fs()...}); 
} 

Ensuite, vous pouvez l'appeler comme

myThing.runFuncs(lambda1, lambda2); 

Demo

+0

ok ça a l'air cool. C'est un modèle variadique, non? Que se passe-t-il avec la partie '{fs() ...}'? Je suppose que c'est juste appeler toutes les fonctions, mais comment ça s'appelle? Et pourquoi doit-il être enveloppé dans des accolades? – Taylor

+1

[Expansion du paquet de paramètres] (http://en.cppreference.com/w/cpp/language/parameter_pack#Pack_expansion), dans une liste d'accolades. Il appelle le constructeur 'vector' en prenant' initializer_list', comme dans 'std :: vector ({1.0, 2.0, 3.0})'. L'expansion elle-même n'a pas besoin d'être entourée d'accolades - celles-ci font partie de la syntaxe de la liste d'initialisation, pas de la syntaxe d'extension du pack. –