假设我有代码:
template<size_t num> void actLoop(float* result, const float* rvector,
size_t* xs, size_t indexIn=0)
{
for(xs[num]=0; xs[num]<N; ++xs[num])
{
size_t index = indexIn+xs[num]*strides[num];
if(num>0)
actLoop<num-1>(result,rvector,xs,index);
else
result[index] = work(rvector,index,xs);
}
}
它应该创建嵌套级别为num
的嵌套循环。当我尝试编译它时,我得到有关递归过深的编译器错误,即编译器似乎没有消除if(0&gt; 0)语句。
是否有一种很好的方法可以实现这一目标,而不必为num=0
创建单独的专业化?
答案 0 :(得分:5)
if( num > 0 )
是运行时条件。递归发生在编译时。所以不,没有办法避免num = 0
的专业化。
为什么创建num = 0
的专业化?
答案 1 :(得分:3)
有一种方法,Andrei Alexandrescu在Going Native 2013的一次演讲中提出了这个问题:
template<size_t num> void actLoop(float* result, const float* rvector,
size_t* xs, size_t indexIn=0)
{
for(xs[num]=0; xs[num]<N; ++xs[num])
{
size_t index = indexIn+xs[num]*strides[num];
if(num>0)
actLoop<(num > 0 ? num-1 : num)>(result,rvector,xs,index);
else
result[index] = work(rvector,index,xs);
}
}
如果actLoop
为num
,则指的是0
的同一实例化,从而打破了无限的实例化。
答案 2 :(得分:2)
这里出现问题的最明显迹象是num
。你不需要描述的nonce名称和你不能混淆的名字之间存在差异。你试图使num
意味着两个不同的东西,剩下的循环层数和你用于簿记的数组索引。
template<size_t nloops>
void actLoop(float* result, const float* rvector, size_t* xs, size_t index=0)
{ // loop layers (nloops>=1): loop
auto xs_index=nloops-1;
for ( int i=0 ; i < N ; ++i ) {
xs[xs_index] = i;
actLoop<nloops-1>(result, rvector, xs, index + i*strides[xs_index]);
}
}
template<>
void actLoop<0>(float* result, const float* rvector, size_t* xs, size_t index)
{ // no loops left: work
result[index] = work(rvector,index,xs);
}
答案 3 :(得分:0)
不阻止使用最终递归调用进行完全内联的方法是:
template<size_t num> void actLoop(float* result, const float* rvector,
size_t* xs, size_t indexIn=0, std::false_type )
{
result[index] = work(rvector,index,xs);
}
template<size_t num> void actLoop(
float* result,
const float* rvector,
size_t* xs,
size_t indexIn=0,
std::true_type unused=std::true_type()
)
{
for(xs[num]=0; xs[num]<N; ++xs[num])
{
size_t index = indexIn+xs[num]*strides[num];
actLoop<num-1>(result, rvector, xs, index, typename std::conditional<(num>0), std::true_type, std::false_type>::type());
}
}
我们在-1情况下调用不同的重载而不是其他情况。
另一种方法是将函数调用退回到template class
,您可以专注于num = -1
案例。
答案 4 :(得分:0)
使用现代C ++(自C ++ 17起)可以更直接地解决此问题:使用if constexpr
语句。这是OP中代码的修改版本(带有一些虚拟包装程序以使其可编译):
#include <stddef.h>
float work(const float*,size_t,const size_t*) { return 0; }
const unsigned N=5;
size_t strides[10];
template<size_t num> void actLoop(float* result, const float* rvector,
size_t* xs, size_t indexIn=0)
{
for(xs[num]=0; xs[num]<N; ++xs[num])
{
size_t index = indexIn+xs[num]*strides[num];
if constexpr(num>0)
actLoop<num-1>(result,rvector,xs,index);
else
result[index] = work(rvector,index,xs);
}
}
int main()
{
float res[10], rvec[10]={};
size_t xs[10], str[10]={};
actLoop<5>(res,rvec,xs);
}