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

reverse call in C++ template function

本文关键字:调用 函数 c++      更新时间:2023-10-16

我不能在模板函数内部进行反向调用,尽管传递给它的参数似乎没有问题。第一个是头文件:

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

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

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

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

是非法的

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

如果您正在尝试实现编译时模板递归,则必须使用编译时技术(与运行时分支相反)来实现它。在你的情况下,它可以通过使用显式专门化来完成,即通过为大小为1的数组添加单独的显式专门化的printArray非递归版本。

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的模板参数。您可以将函数调用为printArray(arr)。编译器将推导出size .