内置阵列的大小是什么类型的?

时间:2014-07-18 13:26:28

标签: c++ arrays templates

在推导非类型模板参数时,比如nn的类型必须与参数和参数完全匹配。所以下面的代码不会编译(至少在GCC和clang上):

#include <array>
template <int n> void f(std::array<int, n> const&) {}
int main() {
  std::array<int, 3> arr;
  f(arr);
}

这是因为std::array被声明为

template <typename T, std::size_t n> class array;

而不是

template <typename T, int n> class array;

但是,要捕获内置数组的大小,似乎任何整数类型都可以。以下所有关于GCC,clang和VC ++的工作:

template <typename T, char n > void f(T (&)[n]);
template <typename T, short n> void f(T (&)[n]);
template <typename T, int   n> void f(T (&)[n]);
...

那么,严重的是,内置数组的大小是否过载了?

3 个答案:

答案 0 :(得分:6)

来自§8.3.4[dcl.array] / 1:

  

如果常量表达式(5.19)   如果存在,它应该是std :: size_t类型的转换常量表达式,并且其值应大于零。常量表达式指定数组(元素的数量)的边界

类型为std::size_t

其他类型一般工作的原因是转换是根据§14.3.2[temp.arg.nontype] / 5传入的类型完成的:

  

对于整数或枚举类型的非类型模板参数,将应用转换常量表达式(5.19)中允许的转换。

来自§5.19[expr.const] / 3:

  

整数常量表达式是整数或未整数枚举类型的表达式,隐式转换为prvalue,其中转换后的表达式是核心常量表达式。

     

snip (提及这些可以用作数组边界)

     

T类型的转换常量表达式是一个表达式,隐式转换为T类型的prvalue,其中转换后的表达式是核心常量表达式,隐式转换序列仅包含用户定义的转换,lvalue-to-rvalue转换(4.1),整体促销(4.5)和积分转换(4.7),而不是缩小转化次数(8.5.4)。

最后,§4.7[conv.integral] / 3:

  

如果目标类型已签名,则该值如果可以在目标类型(和位字段宽度)中表示,则不会更改;否则,该值是实现定义的。

如果绑定的值适合您的参数类型,它将成功转换。如果没有,您将最终获得绑定的实现定义值。

数组是一种特殊情况,如ectamur's answer中指出的那样:

§14.8.2.5[temp.deduct.type] / 17:

  

如果在具有非类型模板参数的函数模板的声明中,在函数参数列表的表达式中使用非类型模板参数,并且如果推导出相应的模板参数, template-argument类型应该与template-parameter的类型完全匹配,除了从数组绑定推导出的模板参数可以是任何整数类型。

答案 1 :(得分:4)

这包含在14.8.2.5 [temp.deduct.type] 第17段中:

  

17 - [...] []]模板参数类型应与模板参数的类型完全匹配,除了从数组绑定推导出的模板参数可以是任何整数类型。

http://wg21.cmeerw.net/cwg/issue1770中,这种情况有所改进:

  

17 - 如果P的表单包含<i>,并且相应值A的类型与i的类型不同,则扣除失败。如果P的表单包含[i],并且i的类型不是整数类型,则扣除失败。

因此,可以将数组边界推导为任何整数类型,但必须将非类型模板参数推导为模板定义中的实际类型。

实际上,标准的C ++ 11版本中没有任何地方为数组边界指定首选类型;指定数组边界(在 [dcl.array] 中)为“一个整数常量表达式,其值应大于零”。在最近的C ++ 14草案中,这被修改为“ std::size_t [...] ”类型的转换常量表达式(5.19);已更改的定义可以追溯到n3306。有点奇怪的是,这种变化表现为“后果调整[...]以保持一致性”,这意味着编辑们认为size_t是正确的类型是显而易见的。

答案 2 :(得分:0)

C数组的大小是编译时常量,由编译器管理(运行时没有关于C数组大小的信息),当您实例化模板时,编译器只检查实际大小是否适合提供的模板类型。例如:

template <typename T, char n > void f(T (&)[n]) {}

int main() { 
  int a[1000];
  f(a);
}

即使int a[20];成功,这也会失败。