2011-05-17 5 views
4

J'ai un certain nombre d'algorithmes pour la détection de communauté sur les graphiques que je veux maintenant visualiser. Cette visualisation nécessite de "détourner" ces algorithmes pendant qu'ils exécutent et enregistrent ce qu'ils font. Spécifiquement cela signifiera passer une référence à un std::vector<graph_partition> comme argument à ces algorithmes, et ajouter à ce vecteur pendant que l'algorithme continue.Gérer efficacement les fonctions (logging/non-logging) légèrement différentes

Par conséquent, pour chaque algorithme (qui sont généralement juste des fonctions), je devrais ajouter un autre argument pour le &std::vector<graph_partition>, et une ou deux lignes de code pour la journalisation.

Je ne veux pas toujours/besoin de se connecter cependant, et ainsi de le faire de manière intelligente s'est avéré non-trivial. J'ai pensé:

  • Rédiger les versions de journalisation distinctes de chaque algorithme: Le problème est ici que je vais me répéter massivement, puisque 95% des diagraphie et les fonctions non-exploitation forestière sera le même. Vous pourriez dire que mon code devrait être si modulaire qu'aucune répétition ne devrait se produire, mais en pratique, à moins d'avoir beaucoup de petites fonctions triviales, je devrais me répéter.
  • Avoir une seule fonction avec un argument conditionnel pour décider s'il faut se connecter ou non: Le problème est que puis-je passer pour &std::vector<graph_partition> quand je ne veux pas l'utiliser? Aussi (probablement minuscule) coup d'exécution de l'évaluation continue conditionnelle.
  • Quelques magies de macro: Les macros sont un peu maléfiques et préfèreraient les éviter si possible.
  • Connectez-vous par défaut, ignorez si je n'en ai pas besoin: Pratique mais inutile, à la fois en termes d'autonomie et d'espace.

Des idées ou des réflexions à ce sujet seraient appréciées. Passez un pointeur vers une classe de consignation parent pour chaque fonction.

+0

Ou peut-être que je pourrais utiliser des modèles variés, cela pourrait être intéressant? – zenna

+0

Ai-je bien compris, que vous passez la fonction/l'objet de journalisation en tant que paramètre? – Xeo

+0

Eh bien, je n'ai encore rien fait. En enregistrant, je veux dire simplement passer dans le vecteur en tant que paramètre et l'ajouter à la fonction. – zenna

Répondre

2

Si vous souhaitez utiliser des modèles, je ne pense pas que vous ayez vraiment besoin de modèles variadic. Si vous êtes heureux de recompiler pour commuter la connexion et désactiver:

struct NoLogging { 
    void log(const graph_partition &) {} 
}; 

struct Logging { 
    std::vector<graph_partition> vec; 
    void log(const graph_partition &p) { 
     vec.push_back(p); 
    } 
}; 

template <typename Logger> 
void some_algorithm(Logger &logger) { 
    // do some stuff 
    logger.log(something); 
} 

// optionally, for convenience 
void some_algorithm() { 
    NoLogging l; 
    some_algorithm(l); 
} 

// user writes: 
some_algorithm(); 

// or 

Logging l; 
some_algorithm(l); 
// do something with l.vec 

La différence entre ceci et « Consigner par défaut, même si je ne pas besoin », est qu'un même vaguement décent compilateur va complètement supprimer les appels à log en some_algorithm<NoLogging>, car il peut voir qu'ils ne font rien. Si vous ne voulez pas avoir à recompiler, vous pouvez avoir un basculement d'exécution entre les deux différents ensembles d'instanciations - il peut ou non être pratique de le faire via une interface polymorphe qui fournit tous les algorithmes et a deux classes dérivées, à partir d'un modèle comme ceci:

template <typename Logger> 
struct ConcreteAlgorithms : public Algorithms { 
    Logger logger; 
    static void some_algorithm() { 
     ::some_algorithm(logger); 
    } 
    // more algorithms 
}; 

Algorithms *get_algorithms(bool with_logging) { 
    if (with_logging) { 
     return new ConcreteAlgorithms<Logging>; 
    } else { 
     return new ConcreteAlgorithms<NoLogging>; 
    } 
} 

Cependant, à ce stade, vous allez avoir le ballonnement de code de deux versions différentes des algorithmes, vous préférerez peut-être faire l'enregistreur polymorphes et prendre le temps d'exécution (probablement minime) à la place, selon la réponse de Mark.

+0

+1 Cet idiome basé sur des modèles est parfois appelé "classe de politique". –

1

Avoir un enfant de la classe de journalisation qui implémente la fonction de journalisation comme un do-nothing, et utilisez celui-ci lorsque vous n'avez pas besoin de vous connecter. La classe de journalisation réelle serait également un enfant et contiendrait le vecteur ou une référence à celui-ci.

+0

ou peut-être - si vous ne voulez pas déranger les clients qui n'ont pas besoin de se connecter - d'avoir une valeur par défaut pour ce paramètre de '0' ou' NullLogger() ' – davka

+0

@davka, j'aime l'idée d'un paramètre par défaut . Je ne ferais pas 0 (NULL) cependant, parce que ce n'est pas mieux que de passer un drapeau. –

Questions connexes