循环中的模板元图
Template Metaprogramming in loop?
几分钟前,我是预言三词算法问题。下面的代码(算法问题的具体逻辑并不重要,因此我们需要知道的只是主要功能上方的代码只是TMP):
#include <array>
#include <algorithm>
#include <iterator>
#include <iostream>
constexpr int digit_in_ones[10] = { 6, 2, 5, 5, 4, 5, 6, 3, 7, 6 };
constexpr int createOneD(int index);
template<int ...>
struct seq
{
};
template<int A, int ...B>
struct gens : gens<A - 1, A - 1, B...>
{
};
template<int ...S>
struct gens<0, S ...>
{
typedef seq<S...> type;
};
template<int N>
class oneDArrayMaker
{
private:
typedef typename gens<N>::type sequence;
template<int ...S>
static constexpr std::array<int, N> make(seq<S ...>)
{
return std::array<int, N>{ {createOneD(S)...}};
}
public:
static constexpr std::array<int, N> oneDArr = make(sequence());
};
template<int N>
constexpr std::array<int, N> oneDArrayMaker<N>::oneDArr;
constexpr int createOneD(int index)
{
return index < 10 ?
digit_in_ones[index] :
digit_in_ones[(index % 100) / 10] + digit_in_ones[index % 10] +
(index >= 100 ? digit_in_ones[index / 100] : 0);
}
int main()
{
int n{}, ans{};
scanf("%d", &n);
for (int i = 0; i < 800; i++)
{
for (int j = 0; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + oneDArrayMaker<800>::oneDArr[j] + (i+j < 800 ? oneDArrayMaker<800>::oneDArr[i+j] : 100) + 4;
if (temp == n)
{
ans++;
}
}
}
printf("%d", ans);
}
我知道loop
和if
(排除constexpr function
和if constexpr
)是运行时,而不是编译时间。因此,诸如template specialization
之类的技巧是if
和loop
的变电站。我从本文中学到了关于模板编程中if
的愚蠢使用的教训 - 使用C 11编译时间循环 - 创建一个广义static_for实现,此处代码:
#include <iostream>
template<int index> void do_stuff()
{
std::cout << index << std::endl;
}
template<int max_index, int index = 0> void stuff_helper()
{
if (index <= max_index)
{
do_stuff<index>();
stuff_helper<max_index, index + 1>();
}
}
int main()
{
stuff_helper<100>();
return 0;
}
作者的解释:
在表面上,IF语句看起来可能是终止递归的原因,例如如何使用"正常"运行时的递归算法。但这就是问题。运行时有效的工作在编译时不起作用。
这是一个无限的循环,仅停止,因为编译器将自己限制在一定的递归深度上。在Clang中,我会遇到错误致命错误:递归模板实例化超过256的最大深度。
糟糕... ,我只是说我知道的...
最后,这是我的问题:
现在,模板的实例化(特别是两张)正在编译时间。因此,所有模板在浇头代码中的实例化都应在编译时:
for (int i = 0; i < 800; i++)
{
for (int j = 0; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + ... // 800 * 800 instantiations should be deternimated at compile time
...
}
...
}
我们知道1.这里的两个for loop
是运行时ah,尽管它不超出模板功能/类的定义,并且仅在主函数中。2.每个auto temp = oneDArrayMaker<800>::oneDArr[i] + ...
都应在编译时初始化,因此应在编译时降低800 * 800实例。
Q1:主要功能中的运行时循环与799*799编译时间模板初始化?
我的假设:在编译时,编译器知道循环的深度,因此只需展开循环,在运行时没有循环。但是我坚持认为,两个循环(I和J)在运行时也无法降低,我将主要功能更改为:
int main()
{
int n{}, ans{}, i{}, j{};
scanf("%d", &n);
scanf("%d %d", &i, &j);
std::cout << n << " " << i << " " << j << std::endl;
for (; i < 800; i++)
{
for (; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + oneDArrayMaker<800>::oneDArr[j] + (i+j < 800 ? oneDArrayMaker<800>::oneDArr[i+j] : 100) + 4;
if (temp == n)
{
ans++;
}
}
}
printf("%d", ans);
}
现在,由于scanf
,必须在运行时降低i
和j
。我只是将额外的两个0
传递给stdin。
这是Alter Main功能之后的实时示例,输出为12
(正确的答案是128)
它成功地编译了,没有生成警告。让我感到困惑的是,输出与原始代码不同(实时代码,其输出为128
(等于Rigth答案)。
在Dubug之后,我发现关键是在更改代码之后,for (; i < 800; i++)
仅一次启用i = 0
,而它应该剥离1~799
,这是12
的原因,而不是128
。
Q2:如果在运行时无法降低循环的深度,并且TMP代码生存在循环中,将会发生什么?
Q3:如何解释输出12
更新:
Q3已由@Scott Brown解决,我很粗心。
Q1和Q2仍然使我感到困惑
您忘了在' for (; j < 800; j++)
'之前重置J。
int main()
{
int n{}, ans{}, i{}, j{};
scanf("%d", &n);
scanf("%d %d", &i, &j);
std::cout << n << " " << i << " " << j << std::endl;
int j_orig = j;// here
for (; i < 800; i++)
{
j = j_orig;// and here
for (; j < 800; j++)
{
auto temp = oneDArrayMaker<800>::oneDArr[i] + oneDArrayMaker<800>::oneDArr[j] + (i+j < 800 ? oneDArrayMaker<800>::oneDArr[i+j] : 100) + 4;
if (temp == n)
{
ans++;
}
}
}
printf("%d", ans);
}
- 如何循环打印顶点结构
- 如何在C++中从两个单独的for循环中添加两个数组
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 正在尝试了解输入验证循环
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 循环后如何继续阅读
- Ardunio UNO解决了多个重叠的定时器循环
- Eigen如何在容器循环中干净地附加矩阵
- 在某些循环内使用vector.push_back时出现分段错误
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 为什么我的for循环不能正确获取argv
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- while循环中while循环的时间复杂度是多少
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 为什么在这个代码结束循环中没有得到结束
- 在基于范围的for循环中使用结构化绑定声明
- 用于C++中带有数组和指针的循环
- 循环中的随机函数
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 在循环C++中指定字符串之后,不会打印该字符串