在具有不同输出的过程相似的函数中防止代码重复?
Preventing code duplication in procedurally similar functions that have different output?
我们有一些函数 foo(g, v, output)
接受顶点 v
搜索一些图 g
附近的顶点和 returns 一些关于路径的信息向量(步骤) 在那次搜索中花费了。
现在这些步骤是一个大结构(越来越大),我们通常只需要每个步骤的一些特定数据(结构的成员)。
问题是我们现在有多个函数(重复代码)在做这样的事情:
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
}
你怎么能做到只有一个函数可能接受枚举和 returns 一个由所需字段填充的向量?
问题是每个字段的类型不同。除此之外,我们复制 (1)、(2) 和 (3) 的大部分内容。
* 实际上更糟,因为我们实际上需要对每个 v
进行测试,所以有一个调用 foo_xs
的函数,一个调用 foo_ys
的函数等等。 ..
一个选项可以是传递一个回调函数,该函数在路径的每一步都被调用。
然后您将提供几个函数,用所需的字段填充向量。不幸的是,向量需要是抽象的。
或者,为您需要的不同字段类型使用模板。这将避免重复源代码。
您还可以考虑使用所需节点的引用向量,并将各个字段作为 post 处理操作传输。
像这样的东西应该可以工作:
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;
}
很难多说,因为你提供的信息不够
为了解决这个问题,boost-graph使用了visitor
的概念。每个图算法使用一个访问者类型,并在发生图遍历事件时调用访问者的方法。
例如,DFS 访问者必须为 discover vertex
事件定义一个方法,为 finish vertex
事件定义另一个方法。
在您的情况下,您将为每个 foo_get_XXX()
函数定义一个访问者实现,并且该访问者只会报告有用的信息。
参考资料
我们有一些函数 foo(g, v, output)
接受顶点 v
搜索一些图 g
附近的顶点和 returns 一些关于路径的信息向量(步骤) 在那次搜索中花费了。
现在这些步骤是一个大结构(越来越大),我们通常只需要每个步骤的一些特定数据(结构的成员)。
问题是我们现在有多个函数(重复代码)在做这样的事情:
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
}
你怎么能做到只有一个函数可能接受枚举和 returns 一个由所需字段填充的向量?
问题是每个字段的类型不同。除此之外,我们复制 (1)、(2) 和 (3) 的大部分内容。
* 实际上更糟,因为我们实际上需要对每个 v
进行测试,所以有一个调用 foo_xs
的函数,一个调用 foo_ys
的函数等等。 ..
一个选项可以是传递一个回调函数,该函数在路径的每一步都被调用。
然后您将提供几个函数,用所需的字段填充向量。不幸的是,向量需要是抽象的。
或者,为您需要的不同字段类型使用模板。这将避免重复源代码。
您还可以考虑使用所需节点的引用向量,并将各个字段作为 post 处理操作传输。
像这样的东西应该可以工作:
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;
}
很难多说,因为你提供的信息不够
为了解决这个问题,boost-graph使用了visitor
的概念。每个图算法使用一个访问者类型,并在发生图遍历事件时调用访问者的方法。
例如,DFS 访问者必须为 discover vertex
事件定义一个方法,为 finish vertex
事件定义另一个方法。
在您的情况下,您将为每个 foo_get_XXX()
函数定义一个访问者实现,并且该访问者只会报告有用的信息。
参考资料