为啥模板参数推导在 C++ 中不起作用?

Posted

技术标签:

【中文标题】为啥模板参数推导在 C++ 中不起作用?【英文标题】:Why template argument deduction doesn't work in C++?为什么模板参数推导在 C++ 中不起作用? 【发布时间】:2021-12-06 14:16:24 【问题描述】:

我对 C++ 中的模板参数推导有疑问。 我不知道为什么下面的示例不起作用。 样本:

#include <iostream>

template<size_t n>
void PrintArray(const int arr[n]) 
    for (int i = 0; i < n; i++)
        printf("%d\n", arr[i]);


int main() 
    int arr[5] = 1, 2, 3, 3, 5;

    PrintArray<>(arr);
    return 0;

编译器打印这个错误:

main.cpp: In function 'int main()':
main.cpp:12:21: error: no matching function for call to 'PrintArray(int [5])'
     PrintArray<>(arr);
                     ^
main.cpp:4:6: note: candidate: template<unsigned int n> void PrintArray(const int*)
 void PrintArray(const int arr[n]) 
      ^~~~~~~~~~
main.cpp:4:6: note:   template argument deduction/substitution failed:
main.cpp:12:21: note:   couldn't deduce template parameter 'n'
     PrintArray<>(arr);

我发现如果我通过引用传递参数,代码就会起作用,所以函数签名变成这样:

void PrintArray(const int (&arr)[n])

但是为什么呢?您能否解释一下为什么当数组按值传递时,编译器无法预测第一个样本中的数组大小?

【问题讨论】:

【参考方案1】:

这个函数声明

void PrintArray(const int arr[n]) 

等价于

void PrintArray(const int *arr) 

由于编译器将具有数组类型的参数调整为指向数组元素类型的指针。

来自 C++ 14 标准(8.3.5 函数)

5 一个名称可用于多个不同的功能 单一范围;这是函数重载(第 13 条)。全部 函数的声明应在返回中完全一致 类型和参数类型列表。确定函数的类型 使用以下规则。每个参数的类型(包括 函数参数包)由其自身确定 decl-specifier-seq 和声明符。 确定类型后 每个参数,任何类型为“T 数组”或“函数”的参数 返回T”调整为“指向T的指针”或“指向函数的指针” 返回 T,”。 生成参数列表后 类型,任何修改参数类型的*** cv 限定符都是 形成函数类型时删除。结果列表 转换后的参数类型以及是否存在 省略号或函数参数包是函数的 参数类型列表。 [注:此转换不影响 参数的类型。例如,int()(const int p, decltype(p)) 和 int()(int, const int) 是相同的类型。 - 结尾 注意]

所以无法推导出模板参数n。

像这样声明函数

void PrintArray(const int ( &arr )[n]) 

或者您可以通过显式指定模板参数来调用原始函数,例如

PrintArray<5>(arr);

【讨论】:

以上是关于为啥模板参数推导在 C++ 中不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C++ CLI 索引属性在 C# 中不起作用?

为啥高度参数在标签小部件中不起作用?

为啥速记参数名称在这个 Swift 闭包中不起作用?

相对路径在 Xcode C++ 中不起作用

当我将可选参数传递给视图时,为啥我的 CSS 静态文件在 Django 中不起作用?

将参数传递给可执行文件在 C++ 中不起作用