我有一个名为 Writer
的类,其函数为 writeVector
,如下所示:
void Drawer::writeVector(vector<T> vec, bool index=true)
{
for (unsigned int i = 0; i < vec.size(); i++) {
if (index) {
cout << i << "\t";
}
cout << vec[i] << "\n";
}
}
我'm trying not to have a duplicate code, while still worrying about the performance. In the function, I'我在 for
-loop的每一轮都进行 if (index)
检查,即使结果总是一样的 . 这是针对"worrying about the performance"的 .
我可以通过将支票放在我的 for
-loop之外来轻松避免这种情况 . 但是,我会得到大量重复的代码:
void Drawer::writeVector(...)
{
if (index) {
for (...) {
cout << i << "\t" << vec[i] << "\n";
}
}
else {
for (...) {
cout << vec[i] << "\n";
}
}
}
所以这些对我来说都是"bad"解决方案 . 我想知道如何在我的程序中使用它,我仍然需要 if
检查以查看要调用哪一个...
根据问题,多态似乎是一个正确的解决方案 . 但是我看不出我该怎么用呢 . 解决这类问题的首选方法是什么?
这不是一个真正的计划, I'm just interested in learning how this kind of problem should be solved.
4 回答
Pass in the body of the loop as a functor. 它在编译时被内联,没有性能损失 .
传递变化的想法在C标准库中无处不在 . 它被称为 strategy pattern.
如果您被允许使用C 11,您可以执行以下操作:
这段代码并不完美,但你明白了 .
在旧的C 98中它看起来像这样:
同样,代码远非完美,但它给你的想法 .
如果确实如此,分支预测器在预测(常量)结果方面没有问题 . 因此,这只会在前几次迭代中导致错误预测的轻微开销 . 在性能方面无需担心
在这种情况下,为了清晰起见,我主张将测试保持在循环内 .
为了扩展Ali的答案,这是完全正确的,但仍然复制了一些代码(循环体的一部分,不幸的是,在使用策略模式时难以避免)...
在这种特殊情况下,代码重复并不多,但是有一种方法可以减少它,它会派上用场 if the function body is bigger than just a few instructions .
关键是使用编译器执行 constant folding / dead code elimination 的能力 . 我们可以通过手动将
index
的运行时值映射到编译时值(当只有有限数量的情况时很容易做到 - 在这种情况下为2)并使用非类型模板参数编译时间:这样我们最终得到的编译代码相当于你的第二个代码示例(外部
if
/内部for
),但没有自己复制代码 . 现在我们可以使writeVector
的模板版本变得如我们想象的那样复杂,总会有一段代码需要维护 .请注意模板版本(以非类型模板参数的形式采用编译时常量)和非模板版本(以运行时变量作为函数参数)如何重载 . 这允许您根据需要选择最相关的版本,在两种情况下都具有相似且易于记忆的语法:
在大多数情况下,您的代码已经具有良好的性能和可读性 . 一个好的编译器能够检测循环不变量并进行适当的优化 . 请考虑以下与您的代码非常接近的示例:
我使用以下命令行来编译它:
然后,让我们转储汇编:
write_vector
的结果程序集是:我们可以看到,在函数的乞求时,我们检查值并跳转到两个可能的循环之一:
当然,这仅在编译器能够检测到条件是实际不变的情况下才有效 . 通常,它完全适用于标志和简单的内联函数 . 但如果条件“复杂”,请考虑使用其他答案的方法 .