为什么C++模板数组长度推导需要像“f(T (&a)[N]”一样?

Imm*_*ant 2 c++ arrays templates pass-by-reference pass-by-value

使用C++模板来知道C风格数组的长度,我们需要这个:

#include<stdio.h>
template<class T,size_t N>
size_t length(T (&a)[N]){ return N; }
int main() {
    int fd[2];
    printf("%lld\n", length(fd));;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它可以工作,打印2。我的问题是关于语法的。

在 的声明中length,为什么参数应该像(&a)[N], 一样a[N]不起作用?

如果我改为

template<class T,size_t N>
size_t length(T a[N]){ return N; }
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会会说:

template argument deduction/substitution failed:
couldn't deduce template parameter 'N'
Run Code Online (Sandbox Code Playgroud)

为什么这里需要&在数组标识符周围添加一个额外的大括号,这背后的模板规则/语法规则是什么?

感谢详细的解释。

Vla*_*cow 6

在这个函数声明中

template<class T,size_t N>
size_t length(T a[N]){ return N; }
Run Code Online (Sandbox Code Playgroud)

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

也就是说这个声明实际上相当于

template<class T,size_t N>
size_t length(T *a){ return N; }
Run Code Online (Sandbox Code Playgroud)

另一方面,在此调用中用作参数表达式的数组

length(fd)
Run Code Online (Sandbox Code Playgroud)

隐式转换为指向其第一个元素的指针。

因此编译器无法推导出模板非类型参数 N 的值。

当参数被声明为引用时,则不会发生如上所述的调整和隐式转换。该引用用作数组的别名。

请注意,要使用size_tC 函数输出无符号整数类型的对象printf,您需要使用转换说明符zu而不是lld