【问题标题】:Array decay to pointers in templates数组衰减到模板中的指针
【发布时间】:2009-12-08 00:08:01
【问题描述】:

请考虑以下代码:

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

【问题讨论】:

  • 你在哪里找到 C++ 编译器 sizeof(int) == 1?第二个电话我得到 108。
  • 是的,当然 gcc 已经移到了 4 字节整数;-) 我在生成测试用例时引入了一个错误。
  • 我很惊讶第二次调用编译。您不能在 C++ 中按值传递数组。 [编辑:啊,T 具有数组类型,但sizeof(x) 仍会输出 8 或 4。没关系。 :)]
  • 不错的 necro 评论 :-) 你只是在浏览我的旧问题吗? :-) 第二种情况是将数组作为参考传递,这是我问的时候没有意识到的。查看接受的答案

标签: c++ templates


【解决方案1】:

使用参数的引用类型

template<typename T> void f(const T& x) 
{
  std::cout << sizeof(T);
}

在这种情况下,数组类型不会衰减。

同样,如果您将模板 agument T 明确指定为数组引用类型,您也可以防止原始版本的 f 衰减

f<int (&)[27]>(array);

在您的原始代码示例中,强制参数 T 具有数组类型(即非引用数组类型,通过使用 typeof 或通过显式指定类型)不会阻止数组类型衰减。虽然T 本身代表数组类型(如您所见),但参数x 仍将被声明为指针,sizeof x 仍将计算为指针大小。

【讨论】:

  • 是的,但我使用的是 sizeof(T)。无论如何,感谢您的快速回答:-)
【解决方案2】:

这段代码的行为由 C++14 [temp.deduct.call] 解释:

从函数调用中推导出模板参数

模板参数推导是通过将每个函数模板参数类型(称为P)与调用的相应参数类型(称为A)进行比较来完成的,如下所述

然后在下面:

如果P 不是引用类型:

  • 如果A是数组类型,则使用数组到指针标准转换(4.2)产生的指针类型代替A进行类型推导;

对于电话f(array);,我们有A = int[27]A 是一个数组类型。所以根据最后一个要点,推导出的类型Tint *

我们可以从限定符“如果P 不是引用类型”中看到,可以通过将P 设为引用类型来避免这种行为。代码:

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

符号P表示T(&amp;)[N],是一个引用类型;事实证明,这里没有应用任何转换。将T推导出为intx的类型为int(&amp;)[N]


请注意,这仅适用于从参数推导出类型的函数模板。该行为由明确提供的函数模板参数和类模板的规范的单独部分涵盖。

【讨论】:

    【解决方案3】:

    您还可以使用以下模板:

    template <typename T, std::size_t N>
    inline std::size_t number_of_elements(T (&ary)[N]) {
        return N;
    }
    

    如果函数用于非数组类型,这个小技巧会导致编译错误。

    【讨论】:

      【解决方案4】:

      根据您的用例,您可以解决using references

      template<typename T>
      void f(const T& x) {
          std::cout << sizeof(T);
      }
      
      char a[27];
      f(a);
      

      根据需要打印27

      【讨论】:

      • 可能应该使用 const-reference,因为您没有修改 T。
      猜你喜欢
      • 2011-11-14
      • 2021-12-01
      相关资源
      最近更新 更多