У нас есть какая-то функция foo(g, v, output)
которая принимает вершину v
ищет некоторый график g
для близлежащих вершин и возвращает некоторый вектор информации о пути (шагах), который он предпринял во время этого поиска.
Теперь шаги представляют собой большую структуру (становится больше), и мы часто просто хотим получить какой-то конкретный элемент данных (член структуры) для каждого шага.
Проблема в том, что теперь у нас есть несколько функций (дублирующий код), которые делают что-то вроде этого:
foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo (1)
foo(g, v, output); // (2)
// parse output to get only xs // (3)
}
foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo
foo(g, v, output);
// parse output to get only ys
}
foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo
foo(g, v, output);
// parse output to get only zs
}
Как вы могли бы сделать так, чтобы была только одна функция, которая, возможно, принимает перечисление и возвращает вектор, заполненный требуемым полем?
Проблема в том, что каждое поле имеет другой тип. Кроме этого мы дублируем (1), (2) и большую часть (3).
* На самом деле это на самом деле хуже, потому что нам нужно проверять каждый v
так что есть функция, которая вызывает foo_xs
, функция, которая вызывает foo_ys
и так далее…
Можно было бы передать функцию обратного вызова, которая вызывается на каждом шаге пути.
Затем вы бы предоставили несколько функций, которые заполняют вектор требуемым полем. К сожалению, вектор должен быть абстрактным.
В качестве альтернативы, используйте шаблон для различных типов полей, которые вам нужны. Это позволит избежать дублирования исходного кода.
Вы также можете рассмотреть возможность использования вектора ссылок на нужные узлы и передать отдельные поля в качестве операции постобработки.
Чтобы решить эту проблему, boost-graph использует visitor
концепция. Каждый алгоритм графа использует тип посетителя и вызывает методы посетителя, когда происходят события обхода графа.
Например, посетитель DFS должен определить метод для discover vertex
событие и еще один метод для finish vertex
событие.
В вашем случае вы бы определили одну реализацию посетителя для каждого из ваших foo_get_XXX()
функция, и этот посетитель будет только сообщать полезную информацию.
Рекомендации
Примерно так должно работать:
enum Field { xs, ys, zs };
template<Field f>
struct FieldGetter;
template<>
struct FieldGetter<xs> {
typedef int type;
static int get( const BigStructure &o ) { return o.xs; }
}
...
template<Field f, typename T=FieldGetter<f>::type>
std::vector<T> foo_get_xs(g, v, result) {
// initialize vectors needed to catch output from foo
foo(g, v, output);
// parse output to get only ys
std::vector<T> res;
for( const auto &o : output )
res.emplace_back( FieldGetter<f>::get( o ) );
return res;
}
Сложно сказать больше, так как вы не предоставляете достаточно информации