在循环中展开的编译时内的模板参数?

时间:2011-07-19 04:44:37

标签: c++ templates loop-unrolling

维基百科(here)给出了for循环的编译时间... 我想知道我们可以使用类似的for循环与模板语句内... 例如......

是以下循环有效

template<int max_subdomain>
void Device<max_sudomain>::createSubDomains()
{
    for(int i=0; i< max_subdomain; ++i)
    {
        SubDomain<i> tmp(member);
        ...
        // some operations on tmp
        ...
    }
}

SubDomain是一个接受模板参数int的类,这里使用的参数是Device类的成员。

谢谢你的回答...... 既然你知道我想要什么...... 无论如何,我实现了我想要的目标吗?

我终于得到了我想要的.............. 而不是直接使用for循环... 可以改为使用Boost::MPL for_each construct。我还没有实现它,但我猜这提供了一种方法来做我想要的......

我从另一个堆栈溢出问题here中得到了答案......然而同一问题的comment拒绝使用它,因为它会非常慢(当然对于大的循环)。但是..对于不大的循环我不认为应该有任何膨胀......我会尝试代码,让你知道结果....

example

中很好地说明了这种用法

3 个答案:

答案 0 :(得分:8)

有一个标准的解决方案。将迭代器转换为递归。

template<int i>
void Device::createSubDomains()
{
    SubDomain<i> tmp(member);
    // some operations on tmp
    createSubDomains<i-1>();
}
template<>
void Device<-1>::createSubDomains()
{
  // End of recursion.
}

注意:您不能使用运行时if(i!=0) createSubDomains<i-1>();

2017注意:您现在可以使用编译时if constexpr(i!=0) createSubDomains<i-1>();

答案 1 :(得分:2)

即使你已经接受了@iammilind的回答,让我提出另一个答案,因为他为什么i不是编译时常量的推理是不正确的。< / p>

假设你有

    template<unsigned int MAX> struct SubDomain {...};
    ...

并且您想要声明它的实例......

    SubDomain<i> tmp(member);

然后i必须是通常所谓的编译时常量。那是什么?


学究气

标准将术语nontype template argument分配给非类型的模板参数(D'Oh)。

14.3.2 模板非类型参数 [temp.arg.nontype]

  

非类型非模板模板参数的模板参数应为以下之一:
     - 整数或枚举类型的整数常量表达式;或
     - ...... [更多关注,但不相关]

正确的第一点包含进一步研究的参考:an integral constant-expression。这导致我们

5.19 常量表达式 [expr.const]

  

在一些地方,C ++需要表达式来计算整数或枚举常量:作为数组     bounds(8.3.4,5.3.4),作为case表达式(6.4.2),作为位字段长度(9.6),作为枚举器初始化器(7.2),     as static member initializers(9.4.2), 以及整数或枚举非类型模板参数(14.3)

然后,关键是:

  

整数常量表达式只能包含文字(2.13),枚举数,常量变量或静态     使用常量表达式(8.5)初始化的整数或枚举类型的数据成员,非类型模板     整数或枚举类型的参数,以及表达式的大小。


Pedantry申请

如果我们回顾你的循环:

for (int i=...
    ...
    SubDomain<i>

然后我们现在可以观察到那里不允许i。为什么?因为i不是const variable

观察读者现在可能认为你可以绕过这个:

for (int i=...
        ...
        const int I = i;
        SubDomain<I>

但是这真的允许吗?否定,I = i不是整数常量表达式,因为i不是。它有助于实现递归地应用整数常量表达式的规则。

例如,以下是有效代码:

template <int> void foo() {}     
int main () {
    const int ccI = 0;
    const int ccJ = ccI*2;
    const int ccK = ccJ/4;     
    foo<ccK>();
}

但是,如果只将链的一部分设为非常数,则ccK不再被视为整数常量:

template <int> void foo() {}     
int main () {
          int ccI = 0;
    const int ccJ = ccI*2;  // not compile time constant
    const int ccK = ccJ/4;  // same

    foo<ccK>();             // error
}


摘要

因此,在人类可读的形式中,非类型但是(整数)值的模板参数必须是编译时常量:

  • 编译时常量的初始化程序必须只涉及其他编译时常量
  • 文字值是编译时常量
  • 枚举值是编译时常量
  • 函数调用不提供编译时常量(出于某些高级原因)

答案 2 :(得分:0)

<强>重新修改:

我之前的回答是正确的。我试过你的代码,它给出了编译器错误。你无法声明这样的对象,因为i不能保持编译时常量(,因为你打算做 i++)。 template参数必须始终是编译时常量。这是the demo

另请注意,作为编译器优化的一部分,循环展开也是针对正常循环完成的。它不仅限于template s。