我用C ++键入以下代码:
#include <iostream>
template <int n, int i = 0>
class show {
public:
show () {
if (i % 2) {
std::cout << i << std::endl;
show <n-1, i+1>();
}else {
show <n,i+1>();
}
}
};
template <int i>
class show <0, i> {};
int main()
{
show <6>();
}
我认为它将写出6个不能被2整除的第一个数字。相反,我得到一个错误
严重错误:模板实例超过最大100个
如果最多实例化12个实例,为什么会出现此错误?
答案 0 :(得分:5)
尝试
show () {
if ( i % 2 )
std::cout << i << std::endl;
show<n-(i%2 ? 1 : 0), i+1>();
}
或者,如果可以使用C ++ 17,也可以使用
show () {
if constexpr (i % 2) {
std::cout << i << std::endl;
show <n-1, i+1>();
}else {
show <n,i+1>();
}
}
您的代码有问题
show () {
if (i % 2) {
std::cout << i << std::endl;
show <n-1, i+1>();
}else {
show <n,i+1>();
}
}
并不重要,如果i % 2
是或否:show
和show<n-1, i+1>
和show<n, i+1>
都被实现了。因此,实现了许多不必要的show
并达到了模板实例化的最大数量。
C ++ 17引入if constexpr
正是为了避免此类问题。
在C ++ 17之前的版本中,您可以解决
show<n-(i%2 ? 1 : 0), i+1>();
答案 1 :(得分:1)
在功能show()
中:
show () {
if (i % 2) {
std::cout << i << std::endl;
show <n-1, i+1>();
}else {
show <n,i+1>();
}
}
类模板show
在if
子句的两个部分都实例化。
您需要切换到if constexpr
来进行单个正确的实例化:
show () {
if constexpr (i % 2) {
std::cout << i << std::endl;
show <n-1, i+1>();
}else {
show <n,i+1>();
}
}
答案 2 :(得分:1)
要查看发生了什么,让我们尝试“内联”更简单的表达式show<1>()
的实例化:
在第一个递归级别中,这将是我们得到的:
if (0 % 2) {
std::cout << 0 << std::endl;
show <0,1>(); // <-- this will instantiate to a no-op.
} else {
show <1,1>();
}
这是第二个:
if (0 % 2) {
std::cout << 0 << std::endl;
} else {
show <1,1>(); // <-- now this will instantiate
}
第三:
if (0 % 2) {
std::cout << 0 << std::endl;
} else {
if (1 % 2) {
std::cout << 1 << std::endl;
show <0,1>(); // <-- this will instantiate to a no-op.
} else {
show <1,2>();
}
}
第四:
if (0 % 2) {
std::cout << 0 << std::endl;
} else {
if (1 % 2) {
std::cout << 1 << std::endl;
} else {
show <1,2>(); // <-- now this will instantiate
}
}
第五:
if (0 % 2) {
std::cout << 0 << std::endl;
} else {
if (1 % 2) {
std::cout << 1 << std::endl;
} else {
if (1 % 2) {
std::cout << 2 << std::endl;
show <0,2>(); // <-- this will again instantiate to a no-op...
} else {
show <1,3>(); // <-- ... and I'm sure you can see where this is going.
}
}
}
这例证了已经指出的其他答案:模板是代码生成器。这意味着,如果编译器到达模板,它将始终从该模板生成代码,而不管程序在到达模板之前具有任何逻辑。
这是if constexpr
可以防止的。如果if constexpr
处的表达式的值为假,编译器将忽略上述if constexpr
块中的任何代码。
如果没有C ++ 17编译器,则可以使用SFINAE达到相同的结果。