4

我有许多用于在图上进行社区检测的算法,现在我想将它们可视化。这种可视化要求我“劫持”这些算法,同时它们执行并记录它们正在做什么。具体来说,这意味着将对 a 的引用std::vector<graph_partition>作为参数传递给这些算法,并在算法进行时附加到该向量。

因此,对于每个算法(通常只是函数),我需要为 , 添加一个进一步的参数&std::vector<graph_partition>,并为日志添加一两行代码。

但是,我并不总是想要/需要记录,因此以智能方式执行此操作已被证明并非易事。我曾想过:

  • 为每个算法编写单独的日志记录版本:这里的问题是我会大量重复自己,因为 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>,因为它可以看到它们什么都不做。

如果您不想重新编译,则可以在两组不同的实例化之间进行运行时切换 - 通过提供所有算法并具有两个派生类的一些多态接口来执行此操作可能会也可能不方便,从这样的模板:

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

但是,此时您将拥有两个不同版本的算法的代码膨胀,因此根据 Mark 的回答,您可能更喜欢使记录器具有多态性并采用(可能很小的)运行时开销。

于 2011-05-17T16:12:11.637 回答
1

将指向父日志记录类的指针传递给每个函数。拥有一个将日志记录功能实现为无所事事的日志记录类的子项,并在不需要日志记录时使用该子项。真正的日志记录类也将是一个子类,并且将包含向量或对它的引用。

于 2011-05-17T15:57:59.173 回答