C ++模板函数中的反向调用

时间:2012-12-24 07:40:27

标签: c++ templates

我无法在模板函数内部进行反向调用,但传递给它的参数似乎没有问题。 首先是头文件:

#ifndef TestTemplate_TestTemplate_h
#define TestTemplate_TestTemplate_h

template<int size>
void printArray(int (*iarr)[size]);

#include "TestTemplate.cpp"
#endif

第二个是.cpp文件:

#include <iostream>

using std::cout;
using std::endl;
template<int size>
void printArray(int (*iarr)[size]){
    if(size == 1){
        return;
    }
    else{
        const int s = size - 1;
        cout << size << endl;
        int arr[s][s] = {};
        printArray<s>(arr);
    }
}

最后是主文件:

#include <iostream>
#include "TestTemplate.h"
int main(int argc, const char * argv[])
{
    const int size = 4;
    int iarr[size][size]= {{1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}, {1, 2, 3, 4}};
    printArray<size>(iarr);
}

现在我收到了编译错误

no matching function for call to 'printArray'
源文件中的

。 也许我在这里不知道模板编程中的一些语法。希望有人能指出我。非常感谢。

1 个答案:

答案 0 :(得分:4)

使用if之类的运行时结构无法终止模板递归(完全在编译时生成)。编译器总是必须实例化if printArray内的arr分支,即使它“知道”其中一个分支将不会被执行。这意味着您的编译时递归并未真正终止。它可能是无限的。当编译器尝试声明大小为0的数组printArray<1>时,它只会出现编译错误,这是非法的。这就是触发错误的原因。

同样,当编译器生成if时,它会为内部int arr[0][0] = {}; 的两个分支实例化代码,这意味着它将尝试声明

printArray

这是非法的。

您从编译器获取的错误消息具有误导性,可能是因为您的编译器实现了一些非标准扩展,允许它接受零大小的数组。实际上,错误应该由零大小的数组声明触发。

如果您正在尝试实现编译时模板递归,则必须使用编译时技术(而不是运行时分支)来使其达到最低点。在您的情况下,可以通过使用显式特化来完成,即为大小为1的数组添加单独的显式专用非递归版template<> void printArray<1>(int (*iarr)[1]) { }

1

(我不知道为什么你没有为大小void printArray(int (*iarr)[1]) { } 的数组做任何事情,我只是忠实地再现了你想要的功能。)

或者,您可以通过使用普通函数重载而不是显式模板特化来实现相同的效果。声明这个重载版本

printArray

它也将解决问题。 (请记住,在这种情况下,必须在递归template<int size> void printArray(int (*iarr)[size]) { const int s = size - 1; cout << size << endl; int arr[s][s] = {}; printArray<s>(arr); } 模板之前声明。)

当然,现在您不再需要在递归版本中进行分支

printArray

P.S。并且无需在代码示例中明确指定printArray(arr)的模板参数。您可以将您的功能称为size。编译器将推导出{{1}}。