请考虑以下代码:
#include <iostream>
template<typename T>
void f(T x) {
std::cout << sizeof(T) << '\n';
}
int main()
{
int array[27];
f(array);
f<decltype(array)>(array);
}
编者注:使用的原始代码typeof(array)
,但这是一个GCC扩展。
这将打印
8 (or 4)
108
在第一种情况下,数组显然衰减为指针而T变为int*
。在第二种情况下,T被强制为int[27]
。
是否定义了衰变/替代实施的顺序?有没有更优雅的方法强制类型int[27]
?除了使用std :: vector?
答案 0 :(得分:9)
使用参数
的引用类型template<typename T> void f(const T& x)
{
std::cout << sizeof(T);
}
在这种情况下,数组类型不会衰减。
同样,如果您明确指定模板agument f
作为数组引用类型
T
中的衰减
f<int (&)[27]>(array);
在原始代码示例中,强制参数T
具有数组类型(即非引用数组类型,使用typeof
或明确指定类型),不会阻止数组类型衰变。虽然T
本身代表数组类型(如您所见),但参数x
仍将被声明为指针,而sizeof x
仍将评估为指针大小。
答案 1 :(得分:2)
此代码的行为由C ++ 14 [temp.deduct.call]解释:
从函数调用中推导出模板参数
模板参数推导是通过将每个函数模板参数类型(称为
P
)与调用的相应参数的类型(称为A
)进行比较来完成的,如下所述
然后在下面:
如果
P
不是参考类型:
- 如果
A
是数组类型,则使用数组到指针标准转换(4.2)生成的指针类型代替A
进行类型推导;
对于来电f(array);
,我们有A
= int[27]
。 A
是一种数组类型。因此,根据最后一个要点,推导出的类型T
为int *
。
我们可以从限定符中看到&#34;如果P
不是引用类型&#34;通过使P
成为引用类型,可以避免这种行为。对于代码:
template<typename T, size_t N>
void f(T (&x)[N])
符号P
表示T(&)[N]
,它是一种引用类型;事实证明这里没有应用转换。 T
被推断为int
,x
的类型为int(&)[N]
。
请注意,这仅适用于从参数推断出类型的函数模板。对于显式提供的函数模板参数和类模板,该行为由规范的单独部分涵盖。
答案 2 :(得分:1)
根据您的使用案例,您可以解决using references:
template<typename T>
void f(const T& x) {
std::cout << sizeof(T);
}
char a[27];
f(a);
根据需要打印27
。
答案 3 :(得分:1)
您还可以使用以下模板:
template <typename T, std::size_t N>
inline std::size_t number_of_elements(T (&ary)[N]) {
return N;
}
如果在非数组类型上使用该函数,这个小技巧将导致编译错误。