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

发布于 2024-11-24 17:42:27 字数 1292 浏览 2 评论 0原文

维基百科(此处)给出了 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循环)...但是..对于不大的循环我认为不应该有任何膨胀...我会尝试代码并让你知道结果... 。

示例

wikipedia (here) gives a compile time unrolling of for loop.......
i was wondering can we use a similar for loop with template statements inside...
for example...

is the following loop valid

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 is a class which takes in the a template parameter int and here has been constructed with an argument that is a member of the Device class.

Thanks for the answer guys...
now that you know what i want...
is there anyway i achieve what i want to??

i finally got what i wanted..............
instead of using the for loop directly...
one can instead use the Boost::MPL for_each construct. I haven't yet implemented it but I am guessing that this provides a way to do what i wanted.....

I took the answer from another stack overflow question here... However the comment to the same question decries its use because it would be very slow (for large for loops of course)... however.. for loops which are not large i don't think there should be any bloating... i'll try the code and let you know the results....

the use is illustrated well in the example

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寻找一个思念的角度 2024-12-01 17:42:27

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

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();

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

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>();

她如夕阳 2024-12-01 17:42:27

尽管您已经接受了 @iammilind 的答案,但让我提出另一个答案,因为他对 i 不是编译时常量 is 的推理不正确。

假设您有

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

并且想要声明它的一个实例...

    SubDomain<i> tmp(member);

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

迂腐

该标准将术语“非类型模板参数”分配给非类型的模板参数 (D'Oh)。

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

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

对,第一点包含进一步研究的参考:整型常量表达式。这导致我们

5.19常量表达式 [expr.const]

在一些地方,C++ 需要计算结果为整数或枚举常量的表达式:作为数组
边界 (8.3.4, 5.3.4),作为 case 表达式 (6.4.2),作为位字段长度 (9.6),作为枚举器初始值设定项 (7.2),
作为静态成员初始值设定项 (9.4.2)、以及作为整数或枚举非类型模板参数 (14.3)

那么,关键是:

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

迂腐的应用程序

如果我们回顾一下你的循环:

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

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

善于观察的读者现在可能会认为你可以规避这一点:

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>();
}

但如果仅使链的一部分成为非 const,则 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
}

摘要

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

  • 编译时常量的初始值设定项只能涉及其他编译时常量
  • 文字值是编译时常量
  • 枚举值是一个编译时常量
  • 函数调用不会给出编译时常量(出于某些高级原因)

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)
与风相奔跑 2024-12-01 17:42:27

重新编辑

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

另请注意,作为编译器优化的一部分,普通循环也会进行循环展开。它不限于模板

Re-Edit:

My previous answer was correct. I have tried your code, it's giving compiler error. You cannot declare objects like that, as i cannot remain a compile time constant (as you are intending to do i++). template parameter must always be compile time constants. Here is the demo.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文