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

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

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

然而,我并不总是希望/需要登录,因此以智能方式执行此操作已经证明是非平凡的.我想到了:

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

任何关于这些的想法或想法将不胜感激.

最佳答案
如果你喜欢使用模板,我认为你真的不需要可变参数模板.如果您愿意重新编译以打开和关闭日志记录:

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

这与“只是默认日志,即使我不需要它”之间的区别在于,一个甚至模糊的编译器将完全删除登录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的答案取代(可能很小的)运行时开销.

转载注明原文:c – 有效维护略有不同(日志记录/非日志记录)功能 - 代码日志