Эффективно поддерживать слегка отличающиеся (входящие / не входящие) функции - PullRequest
4 голосов
/ 17 мая 2011

У меня есть ряд алгоритмов для обнаружения сообществ на графиках, которые я хочу теперь визуализировать.Эта визуализация требует, чтобы я «взломал» эти алгоритмы, пока они выполняются, и регистрировал, что они делают.В частности, это будет означать передачу ссылки на std::vector<graph_partition> в качестве аргумента этих алгоритмов и добавление к этому вектору по мере выполнения алгоритма.

Поэтому для каждого алгоритма (который обычно является просто функциями) мне понадобитсядобавить еще один аргумент для &std::vector<graph_partition> и одну или две строки кода для ведения журнала.

Однако я не всегда буду хотеть / нуждаться в регистрации, и поэтому интеллектуальное выполнение этого оказалось неэффективным.-тривиален.Я подумал:

  • Напишите отдельные версии журналирования каждого алгоритма: Проблема здесь в том, что я буду повторяться в массовом порядке, так как 95% журналирования и неФункции регистрации будут такими же.Вы могли бы сказать, что мой код должен быть настолько модульным, что повторение не должно происходить, но на практике, если у меня нет множества крошечных тривиальных функций, мне пришлось бы повторяться.
  • Иметь одну функцию с условным аргументом длярешить, регистрироваться или нет : Проблема в том, что я пропускаю &std::vector<graph_partition>, когда я не хочу его использовать?Также (возможно, незначительное) попадание во время выполнения при непрерывной оценке условных выражений.
  • Некоторые макрокоманды : Макросы немного вредны и предпочли бы избегать их, если это возможно.
  • Просто войдите в систему по умолчанию, откажитесь, если мне это не нужно : Удобно, но расточительно, как с точки зрения времени выполнения, так и с точки зрения пространства.

Любые идеи или мысли по этому поводу будут оценены.

Ответы [ 2 ]

2 голосов
/ 17 мая 2011

Если вы хотите использовать шаблоны, я не думаю, что вам действительно нужны 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>;
    }
}

Однако в этот момент у вас будет раздувание кода двух разных версий алгоритмов, поэтому вы можете предпочесть сделать регистратор полиморфным и вместо этого взять (возможно, крошечные) накладные расходы, как и в ответе Марка.

1 голос
/ 17 мая 2011

Передать указатель на родительский класс ведения журнала для каждой функции. Имейте дочерний элемент класса регистрации, который реализует функцию регистрации как ничего не делающую, и используйте ее, когда вам не нужна регистрация. Реальный класс ведения журнала также будет дочерним и будет содержать вектор или ссылку на него.

...