3

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

#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'

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

4

1 回答 1

4

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

同样,当编译器生成 时printArray<1>,它会实例化 inner 的两个分支的代码,这if意味着它将尝试声明

int arr[0][0] = {};

这是非法的。

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

如果您尝试实现编译时模板递归,则必须使用编译时技术(与运行时分支相反)使其触底。在您的情况下,可以通过使用显式特化来完成,即通过添加单独的显式特化非递归版本printArrayfor 数组 size 1

template<>
void printArray<1>(int (*iarr)[1]) {
}

(我不知道你为什么不为 size 的数组做任何事情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);
}

PS 而且没有必要printArray在你的代码示例中明确指定模板参数。您可以将您的函数称为printArray(arr). 编译器会推导出size.

于 2012-12-24T08:17:27.673 回答