4

グラフでコミュニティを検出するためのアルゴリズムがいくつかあり、それらを視覚化したいと考えています。このビジュアライゼーションでは、これらのアルゴリズムを実行してログに記録する間、これらのアルゴリズムを「ハイジャック」する必要があります。具体的には、std::vector<graph_partition>これらのアルゴリズムへの引数として a への参照を渡し、アルゴリズムが進行するにつれてそのベクトルに追加することを意味します。

したがって、各アルゴリズム (通常は単なる関数) に、 の引数と&std::vector<graph_partition>、ログ記録用の 1 ~ 2 行のコードを追加する必要があります。

ただし、常にログを記録したい/必要があるとは限らないため、これをインテリジェントな方法で行うことは自明ではありません。私は考えました:

  • 各アルゴリズムの個別のロギング バージョンを作成する:ここでの問題は、ロギング機能と非ロギング機能の 95% が同じであるため、何度も繰り返すことになることです。私のコードは繰り返しが発生しないようにモジュール化する必要があると言えますが、実際には、小さな些細な関数がたくさんない限り、自分自身を繰り返さなければなりません。
  • ログに記録するかどうかを決定する条件付き引数を持つ単一の関数があります&std::vector<graph_partition>: 問題は、使用したくない場合に何を渡すかです。また、条件を継続的に評価することによる (おそらくごくわずかな) ランタイム ヒット。
  • いくつかのマクロの魔法: マクロは少し悪質で、できれば避けたいものです。
  • デフォルトでログに記録し、不要な場合は破棄します。便利ですが、ランタイムとスペースの両方の点で無駄です。

これらに関するアイデアや考えをいただければ幸いです。

4

2 に答える 2

2

テンプレートを使用したい場合は、可変個引数テンプレートは本当に必要ないと思います。ロギングのオンとオフを切り替えるために再コンパイルしてもよければ:

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

これと「必要がない場合でも、デフォルトでログを記録するだけ」との違いは、漠然とまともなコンパイラでもloginへの呼び出しを完全に削除するsome_algorithm<NoLogging>ことです。

再コンパイルする必要がない場合は、インスタンス化の 2 つの異なるセット間でランタイム スイッチを使用できます。すべてのアルゴリズムを提供し、2 つの派生クラスを持つポリモーフィック インターフェイスを介してこれを行うと便利な場合とそうでない場合があります。次のようなテンプレートから:

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>;
    }
}

ただし、この時点で、アルゴリズムの 2 つの異なるバージョンのコードが肥大化することになるため、Mark の回答に従って、ロガーをポリモーフィックにし、代わりに (おそらく小さい) ランタイム オーバーヘッドを使用することをお勧めします。

于 2011-05-17T16:12:11.637 に答える
1

親ログ クラスへのポインターを各関数に渡します。ロギング機能を何もしないものとして実装するロギング クラスの子を用意し、ロギングが必要ないときにそれを使用します。実際のログ クラスも子になり、ベクトルまたはそれへの参照が含まれます。

于 2011-05-17T15:57:59.173 に答える