【问题标题】:Why a compiler doesn't deduce the template parameter in case of zero array?为什么在零数组的情况下编译器不推导出模板参数?
【发布时间】:2017-02-20 04:24:37
【问题描述】:

我已阅读以下链接如何通过模板函数计算数组的大小:

错误:没有匹配函数调用“size_of_array(int [0])”
std::size_t num = size_of_array(arr);

#include <cstddef>
template <typename T, std::size_t N>
inline std::size_t size_of_array( T (&)[N] ) {
   return N;
}
int main()
{
  int arr[0]={};
  std::size_t num = size_of_array(arr);
}

【问题讨论】:

  • 不在一个类中的零大小数组是非法的。
  • @NathanOliver 我可能是错的,但 iirc 0 大小的数组只允许在 C 中用于可变大小的结构。
  • 只需将初始化替换为 int arr[]={} 或 int arr[0];
  • Clang++ 打印出一个解释:'候选模板被忽略:替换失败...零长度数组在 C++ 中是不允许的'。
  • @krzaq 这可能是我见过的一个扩展。至少在 OP 的情况下是非法的。

标签: c++ arrays templates size


【解决方案1】:

来自标准草案 n4296,§8.3.4 数组:

在声明 T D 中,其中 D 具有以下形式

D1 [ 常量表达式 ] 属性说明符序列

以及标识符的类型 声明 T D1 是“derived-declarator-type-list T”,那么 D的标识符是数组类型;

...

如果常量表达式存在,它应该是一个转换后的常量表达式类型 std::size_t 及其值应大于零。

所以你的代码无效。

【讨论】:

  • 我怀疑相关部分是关于类型推断的那一部分。
  • @skypjack 是的,你是对的,你的回答更好地反映了问题的本质,我 +1。不过值得一提的是,由于使用了零大小的数组,该程序并不正确。
【解决方案2】:

根据[temp.deduct/8](working draft模板参数推导,强调我的):

类型扣除可能因以下原因而失败:
[...]
- 尝试创建元素类型为 void、函数类型、引用类型或抽象类类型的数组,或尝试创建大小为零的数组或负数

零长度数组的类型推导可能会失败(主要是因为零长度数组也是不允许的),这就是您收到错误的原因。
另请注意,在同一段中,我们有以下内容(强调我的)

如果使用替换的参数编写,则无效的类型或表达式是格式错误的,需要诊断

【讨论】:

  • 谢谢。我已经使用 gcc 为 98、03、11、14 标准检查了此代码。但它没有显示关于定义零大小数组的错误消息。所以gcc没有实现这个功能。
  • @mhd 我没有收到您的评论,抱歉。 GCC 没有实现哪些功能?你的代码有错误,我已经告诉你原因。
  • 在我上面的评论中,我的意思是零大小的数组,这是一个不正确的代码。我使用 gcc v6.2.1 编译了这段代码int main(){int arr[0]={};},并带有以下选项:-std=c++98; -std=c++03; -std=c++11; -std=c++14;但是 gcc 没有打印关于零大小数组的错误消息。
  • @mhd 使用选项-pedantic。由于编译器扩展,它可以编译,但使用该选项会警告您说它不是有效代码。
猜你喜欢
  • 2017-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
  • 2011-04-27
  • 1970-01-01
  • 2015-09-23
相关资源
最近更新 更多