有效地维护略有不同(日志记录/非日志记录)功能

时间:2011-05-17 15:43:38

标签: c++ modularity code-design

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

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

我并不总是希望/需要记录,因此以智能的方式这样做已经证明是非平凡的。我想到了:

  • 编写每个算法的单独日志版本:这里的问题是我将大量重复自己,因为95%的日志记录和非日志记录功能都是相同的。你可以说我的代码应该是模块化的,不应该重复,但在实践中,除非我有很多微小的功能,否则我必须重复自己。
  • 使用条件参数的单个函数来决定是否记录:问题是当我不想使用它时,我将为&std::vector<graph_partition>传递什么?此外(可能是微不足道的)持续评估条件的运行时命中。
  • 一些宏巫术:宏有点邪恶,如果可能的话,我们更愿意避开它们。
  • 默认只记录,如果我不需要则丢弃:方便但浪费,无论是在运行时还是空间方面。

任何有关这些的想法或想法都将受到赞赏。

2 个答案:

答案 0 :(得分:2)

如果你喜欢使用模板,我认为你真的不需要 variadic 模板。如果您很乐意重新编译以打开和关闭日志记录:

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

这与“默认只记录,即使我不需要它”之间的区别在于,即使是模糊的编译器也会完全删除log中对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>;
    }
}

但是,此时你将会遇到两个不同版本算法的代码膨胀,所以你可能更喜欢使用logger多态并采用(可能很小的)运行时开销,而不是Mark的答案。

答案 1 :(得分:1)

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