【问题标题】:Runtime sized arrays and pointer-decay运行时大小的数组和指针衰减
【发布时间】:2015-06-18 14:31:02
【问题描述】:

我正在通过新的 C++14 运行时大小的数组测试 type_traits 标头中的一些工具,请考虑以下代码:

int g[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

template <typename T> void print(T &t)
{
    std::cout << "Type id:    " << typeid(T).name() << '\n';
    std::cout << "is_array:   " << std::is_array<decltype(T)>::value << '\n';
    std::cout << "is_pointer: " << std::is_pointer<decltype(T)>::value << '\n';
    std::cout << "extent:     " << std::extent<decltype(T)>::value << '\n';
}

int main()
{
    print(g);
    return 0;
}

静态大小的数组g 返回以下输出:

Type id:    A11_i
is_array:   1
is_pointer: 0
extent:     11

未修改的名称 A11_i 我假设这是 A一组 11 类型为 int 的元素,所以这里一切都是正确的,但有了这个新代码:

void f(std::size_t s)
{
    int a[s];
    print(a);
}

int main()
{
    f(5);
    return 0;
}

我遇到了错误:

In function 'void f(std::size_t)':
error: no matching function for call to 'print(int [s])'

note: candidate is:
note: template<class T> void print(T&)
note:   template argument deduction/substitution failed:
note:   variable-sized array type 'int [s]' is not a valid template argument

我没想到可以将 size 参数传递给模板,但我期待自动数组到指针衰减。我猜T &amp; 的参数不适合这种衰减,所以我尝试将模板签名更改为:

template <typename T> void print(T *&t)

结果相似:

In function 'void f(std::size_t)':
error: no matching function for call to 'print(int [s])'

note: candidate is:
note: template<class T> void print(T*&)
note:   template argument deduction/substitution failed:
note:   mismatched types 'T*' and 'int [s]'

而且我注意到运行时大小数组上的大小变量似乎与类型相关(而不是 mismatched types 'T*' and 'int [5]' 我们得到的是 mismatched types 'T*' and 'int [ s]') 这看起来很奇怪。

那么,问题是什么?

  • 为什么我在这个运行时大小的数组中没有得到数组到指针的衰减?
  • 变量是否用于调整运行时大小数组的大小是运行时大小数组类型的一部分还是我误解了错误?

【问题讨论】:

  • 请注意,您使用带有int a[s];的VLA扩展
  • 许多编译器标志或代码规范禁止使用运行时大小的数组。 (例如,我知道带有警告标志的 G++ 禁止它)您的编译器可能拒绝将其用作模板。
  • 为了扩展 Jarod42 的评论,提出了运行时大小的数组,但最终并未包含在最终的 c++14 标准中。
  • 我的错!我真的认为运行时大小的数组包含在 C++14 中(这就是我添加 C++14 标记的原因)。无论如何它不会改变问题:为什么 VLA 在这个例子中不会衰减到指针
  • 它是否适用于精确大小的数组?比如你用a[5];而不是a[s];来测试它?

标签: c++ arrays c++14 variable-length-array


【解决方案1】:

在模板实参推导过程中,仅当函数模板形参的类型不是引用时才使用数组到指针的转换。

§14.8.2.1 从函数调用中推导出模板参数 [temp.deduct.call]

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

2 如果P 不是引用类型:

  • 如果A是数组类型,则使用数组到指针标准转换(4.2)产生的指针类型代替A用于 类型扣除;否则,
  • [...]

【讨论】:

    猜你喜欢
    • 2011-11-14
    • 2021-05-06
    • 2017-05-05
    • 2021-12-01
    相关资源
    最近更新 更多