这个问题只是出于好奇。在递归模板中,如果我们忘记放置一个特定的特化,那么编译器将执行大量迭代,然后在某个时间停止并给出错误,例如,
error: incomplete type ‘X<-0x000000000000001ca>’ used in nested name specifier
在某些情况下,编辑会无限。例如,请参阅以下代码(仅用于说明;使用gcc 4.4.1编译):
template<int I>
struct Infinite
{
enum { value = (I & 0x1)? Infinite<I+1>::value : Infinite<I-1>::value };
};
int main ()
{
int i = Infinite<1>::value;
}
编译器应该足够聪明,不能在某个时间停止吗?
编辑:上面显示的编译错误是针对其他代码的。对于示例代码,编译永远不会停止(但是,我会在两者之间看到这样的错误)
答案 0 :(得分:8)
如果我正确理解你的问题,你希望编译器认识到它永远不会停止迭代。除了在固定数量的嵌套类型之后停止,你想要的东西显然是不可能的:如果我看到它正确你可以用这种方式表达任何turing-machine(至少D
中的模板是完整的)
因此,如果您可以构建一个识别它将在实际尝试之前永久嵌套类型的编译器,那么您将决定对于图灵机不可判定的halting problem。
然而,我很可能会误认为你可以在参数列表中放置任何计算(但是模拟寄存器机似乎是可能的,因为我们可以在一个单独的整数模板参数中编码所有寄存器(是的,{ {1}}是有限的,但非常大,这使得它实际上无限制))。
答案 1 :(得分:6)
使用模板将解析器置于无限循环中并不新鲜。
// Stresses the compiler infinitely
// from: http://www.fefe.de/c++/c%2b%2b-talk.pdf
template<class T> struct Loop { Loop<T*> operator->(); };
Loop<int> i, j = i->hooray;
答案 2 :(得分:1)
编译器应该足够聪明,不能在某个时间停止吗?
如何在某个时间定义短语“?编译器如何在某个时间知道 “”的定义?如果你不明确明确,它怎么知道什么时候必须停止?你首先要通过定义非停止类模板的特化(你所写的是不停止的类模板)来告诉它。
在您的情况下,您必须具有两个类模板的特化,每个方向一个(增加和减少)。像这样:
template<>
struct Infinite<100> //this is to stop template with <I+1> argument
{
enum { value = 678678 }; //see, it doesn't use Infinite<> any further!
};
template<>
struct Infinite<-100> //this is to stop template with <I-1> argument
{
enum { value = -67878 }; //see, it too doesn't use Infinite<> any further!
};
答案 3 :(得分:1)
编译器执行您要求它执行的操作。你要求它进行无限递归 - 它就是这样做的。如果你希望它“在某个时间停止”,你必须要求它在“某个时间”停止,并告诉它你具体的“某个时间”是什么意思。
模板递归与C ++程序中的任何其他递归没有区别:您有责任指定递归到底的位置。