几分钟前,我正在练习琐碎的算法问题。下面的代码(算法问题的具体逻辑并不重要,所以我们只需要知道主函数上面的代码只是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
的愚蠢用法的教训来自 this article-
Compile Time Loops with C++11 - Creating a Generalized static_for Implementation 的模板编程,这里的代码:
#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;
}
作者的解释:
On the surface, it could look like the if statement would be responsible for terminating the recursion, like how this would work with a "normal" run-time based recursion algorithm. But that's the problem. What works at runtime doesn't work at compile time.
This is an infinite loop, and only stops because compilers limit themselves to a certain recursion depth. In clang, I get an error fatal error: recursive template instantiation exceeded maximum depth of 256. You can expect a similar error with your compiler of choice.
哎呀...,我只是陈述我所知道的...
最后,谈到我的问题:
现在模板的实例化(特别是两次解析)是在编译时进行的。因此,最顶层代码中的所有模板实例化都应该在编译时进行:
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
这是运行时,尽管它不在模板函数/类的定义之外,并且仅在主函数中。
2. 每auto temp = oneDArrayMaker<800>::oneDArr[i] + ...
应在编译时初始化,因此 800 * 800 实例化应在编译时确定。
Q1:主函数中的运行时循环是否与 799*799 编译时模板初始化冲突?
我的假设:在编译时,编译器知道循环的深度,因此只需展开循环即可,在运行时没有循环。 但我认为两个循环(i和j)也不能在运行时确定,我将 main 函数更改为:
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);
}
现在i
和j
必须在运行时确定,因为 scanf
。我刚刚通过了额外的两个0
到标准输入。
这里是live example修改 main 函数后,输出为 12
(正确答案是128)
编译成功,没有产生任何警告。让我困惑的是输出与原始代码不同( live code ,其输出为 128
(等于正确答案)。
经过dubug,发现关键是修改代码后,for (; i < 800; i++)
仅执行一次i = 0
,而它应该执行 1~799
,这就是 12
的原因,不是128
。
问题2:如果运行时无法确定for循环的深度并且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++ - 循环中的模板元编程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47460136/