6

维基百科(这里)给出了 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 构造。我还没有实现它,但我猜这提供了一种方法来做我想做的事.....

我在这里从另一个堆栈溢出问题中得到了答案......但是对同一问题的评论拒绝使用它,因为它会非常慢(当然对于大型 for 循环)......但是.. 对于不是大的循环 i不要认为应该有任何腹胀......我会尝试代码并让你知道结果......

示例中很好地说明了用法

4

3 回答 3

8

There's a stadard solution for this. Convert iteration into recursion.

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.
}

Note: you can't use a runtime if(i!=0) createSubDomains<i-1>();.

2017 Note: you can now use a compile-time if constexpr(i!=0) createSubDomains<i-1>();

于 2011-07-19T09:09:48.637 回答
2

Even though you already accepted @iammilind 's answer, let me propose another one, because his reasoning for why i is not compile-time-constant is was not correct.

Suppose you have

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

and you want to declare an instance of it ...

    SubDomain<i> tmp(member);

then i must be a commonly so-called compile-time-constant. What is that?


Pedantry

The standard assigns the term nontype template argument to template arguments that are not types (D'Oh).

14.3.2 Template non-type arguments [temp.arg.nontype]

A template-argument for a non-type, non-template template-parameter shall be one of:
— an integral constant-expression of integral or enumeration type; or
— ... [more follow, but are not relevant]

Right the first point contains a reference for further research: an integral constant-expression. This leads us to

5.19 Constant expressions [expr.const]

In several places, C + + requires expressions that evaluate to an integral or enumeration constant: as array bounds (8.3.4, 5.3.4), as case expressions (6.4.2), as bit-field lengths (9.6), as enumerator initializers (7.2), as static member initializers (9.4.2), and as integral or enumeration non-type template arguments (14.3).

Then, the key is:

An integral constant-expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5), non-type template parameters of integral or enumeration types, and sizeof expressions.


Pedantry application

If we look back at your loop:

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

then we can now observe that i is not allowed there. Why? Because i is NOT a const variable.

The observing reader might now think you can circumvent this:

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

But is this really allowed? Negative, I = i is not an integral constant-expression, because i is not. It helps to realise that the rule for integral constant-expressions is applied recursively.

E.g., the following is valid code:

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

But if make just one part of the chain non-const, then ccK is not considered integral constant anymore:

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
}


Summary

So, in human readable form, template arguments that are not types, but (integer) values, must be compile-time-constant:

  • the initializer of a compile-time-constant must only involve other compile-time-constants
  • a literal value is a compile-time-constant
  • an enum value is a compile-time-constant
  • function-calls don't give compile-time-constants (for some advanced reasons)
于 2011-07-19T10:13:48.517 回答
0

重新编辑

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

Also note that, loop unrolling is done for normal loops also, as part of optimization by compilers. It's not limited to templates.

于 2011-07-19T04:51:50.003 回答