【问题标题】:Why does array type not decay to pointer for class templates?为什么数组类型不会衰减为类模板的指针?
【发布时间】:2016-02-17 04:26:45
【问题描述】:

我们知道arrays decay to pointers in function templates 并且要采用数组类型参数,我们需要使用数组引用来声明我们的函数模板:

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

但是,为什么我们不需要在类模板中声明数组引用参数呢?下面的代码显示了这一点,并在 C++11 下编译。

template<class T>
struct cls_number_of_elements {};

template<class T, std::size_t R>
struct cls_number_of_elements<T[R]> {
  static const int N = R;
};

char ary[] = "12345";
auto const N = cls_number_of_elements<decltype(ary)>::N;
char ar2[N];

【问题讨论】:

  • 我想这可能是因为decltype(ary)使它成为一个数组类型,而模板推导将它衰减为一个指针。
  • 感谢@JamesRoot。尤其令人困惑的是,当函数传递一个数组类型的参数时,template&lt;class T&gt; void array_template(T t)template&lt;class T, std::size_t N&gt; void array_template(T ary[N]) 都会发生衰减。
  • 我不明白你的问题是什么。您的两个代码示例都很好,两者之间没有任何矛盾。您能否展示一段不起作用但您认为它应该起作用的代码?
  • 您链接的问题是关于函数模板推导的,而您的第二个代码示例是关于类模板的。一般来说,函数模板和类模板有不同的规则。

标签: c++ c++11


【解决方案1】:

您所说的“衰减”是从参数推导函数模板参数时发生的事情。我已经发布了更完整的解释here

当你为模板参数显式提供值时,没有推演步骤;您明确提供的值正是参数所采用的值。

使用类模板,永远不会有参数推导;它们必须始终明确提供其参数。

示例:

template<typename T> void f(T t) {}
template<typename T> struct S { void f(T t) {} };

...

int x[27];
f(x);               // Type deduction: decay occurs, T = int *
f<int *>(x);        // No deduction. T = int *
f<int[27]>(x);      // No deduction. T = int[27]
S<int[27]>().f(x);  // No deduction. T = int[27]

在后两种情况下,调整仍然发生。 [temp.deduct]/3 明确重申这一点:当T 是数组类型时,函数参数 T t 意味着t 具有指针类型,其方式完全相同:

void g(int t[27])

实际上指定t 的类型为int *

【讨论】:

    【解决方案2】:

    来自 C++11 标准:

    7.1.6.2 简单类型说明符

    4decltype(e)表示的类型定义如下:

    ——如果e是一个无括号的id-expression或一个无括号的类成员访问(5.2.5),decltype(e)e命名的实体的类型。如果没有这样的实体,或者如果e 命名了一组重载函数,则程序是非良构的;

    ——否则,如果e是一个xvalue,decltype(e)T&amp;&amp;,其中Te的类型;

    ——否则,如果e是一个左值,decltype(e)就是T&amp;,其中Te的类型;

    ——否则,decltype(e)e 的类型。

    给定

    char ary[] = "12345";
    

    decltype(ary)表示ary的类型(一个无括号的id-expression),即char[6]

    decltype 的用户友好描述可以在 http://en.cppreference.com 找到。

    【讨论】:

      【解决方案3】:

      在 C 和 C++ 标准和this answer 之间,看起来解释是:

      4.2 数组到指针的转换

      1. 类型为“NT”或“T 未知边界数组”类型的左值或右值可以转换为右值 类型为“指向T 的指针”。结果是指向数组第一个元素的指针。

      看起来这种转换确实发生在函数模板中推导出的模板参数中

      number_of_elements(ary)
      

      但对于类模板中的模板参数不是

      cls_number_of_elements<char[5]>
      

      和显式类型的函数模板

      number_of_elements<char[5]>(ary)
      

      因为这些类型没有被推断出来。

      【讨论】:

        【解决方案4】:

        查看代码,我有一个非常简短的解释,与类和函数模板之间的区别没有任何关系:

        对于number_of_elements,数组的“类型”是T[N]。示例适用于cls_number_of_elements,其中“类型”为T[R]。 在这两种情况下,T 将变为 charN 分别。 R 变为 6。 您需要 &amp; 的唯一原因是您不能按值传递 c 数组。 (参见@bku_drytt 的分析器)

        【讨论】:

        • 值得澄清的是,您可以按值传递std::array(或作为任何其他类型对象成员的数组)。
        • 感谢您的评论。我更新了我的答案以澄清这不能用于 c 数组。
        猜你喜欢
        • 2016-01-22
        • 2011-11-14
        • 2020-10-07
        • 2014-08-24
        • 2015-03-30
        • 1970-01-01
        相关资源
        最近更新 更多