数组衰减到模板中的指针

时间:2009-12-08 00:08:01

标签: c++ templates

请考虑以下代码:

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

4 个答案:

答案 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是一种数组类型。因此,根据最后一个要点,推导出的类型Tint *

我们可以从限定符中看到&#34;如果P不是引用类型&#34;通过使P成为引用类型,可以避免这种行为。对于代码:

template<typename T, size_t N>
void f(T (&x)[N])

符号P表示T(&)[N],它是一种引用类型;事实证明这里没有应用转换。 T被推断为intx的类型为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;
}

如果在非数组类型上使用该函数,这个小技巧将导致编译错误。