【发布时间】:2020-05-18 09:19:05
【问题描述】:
我需要在循环中执行一段相当复杂的代码,但循环不是在向量上,就是在整数的数值范围上。关于循环类型的决定是在运行时做出的:
if(!int_vector_provided){
for(int i=0;i<N;++i){ // iterate over a numeric range
// complex code depending on i
}
} else {
for(int i: int_vector){ // iterate over a vector
// the same complex code
}
}
问题在于“复杂代码”很难重构为函数,因为它依赖于许多局部和全局变量。将此代码设置为捕获 lambda 也是不可取的,因为这部分对性能至关重要。 如果使用数字范围,它通常非常大(数百万),因此创建此大小的连续数字的向量非常低效。
实际上我需要的是一对迭代器,它们可以分配给向量的开始/结束或数值范围的开始/结束。比如:
SomeCleverIterator b,e;
if(int_vector_provided){
b = int_vector.begin();
e = int_vector.end();
} else {
// Iterators to numeric range
// may be boost::counting_range(0,N) ???
// but how to make boost::range iterators and
// to vector<int>::iterator convertible to the same type??
b = ???;
e = ???;
}
for(SomeCleverIterator it=b;it!=e;it++){
// complex code
}
我尝试使用boost::counting_range,但它的迭代器不能转换为vector<int>::iterator,所以它没有帮助。
我认为这是创建带有迭代器的自定义类模板并为向量和整数对显式实例化它的唯一方法,但这对于这种“微不足道”的问题来说似乎有点过头了。
有没有更好的办法?
【问题讨论】:
-
为什么不将向量迭代为数字范围 [0, size())?如果您像这样更改性能关键代码,也要小心。将 if/else 移入循环可能会与分支预测交互,并可能对性能产生负面影响。
-
@midor 因为向量可能包含任何非连续整数,例如 {1,100,150,1000}
-
XY 问题。而不是
int_vector_provided,应该有2个单独的函数,“复杂代码”部分应该被提取到一个辅助内联函数中。或提供minimal reproducible example 详细说明您的情况。 -
这看起来像是一个经典的 XY 问题。如果您在同一个函数中有两个循环,它们具有相同的主体,那么重构以将“复杂代码”放在一个函数中是微不足道的。如果“复杂代码”取决于调用者中的变量,请将它们作为参数传递(或者,最坏的情况,创建一个包含一组对它们的引用的结构,并将其作为参数传递)。如果“复杂代码”依赖于在调用者之前声明的静态,那么将一个新函数直接放在上面将具有相同静态的可见性。
-
您已经意识到真正的问题是什么。从长远来看,全局变量总是会咬你。最好不要再拖延它并修复它。
标签: c++ iterator range code-duplication