运行时大小的数组和指针衰减

7
我正在测试type_traits头文件中的一些工具,用于新的C++14运行时大小数组,请考虑下面的代码:
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 & 并不适合这种衰减,所以我尝试改变模板签名为:

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]'

我注意到运行时大小的数组中的size变量似乎与类型相关联(而不是我们得到的“类型不匹配'T*'和'int [5]'”而是“类型不匹配'T*'和'int [s]'”),这看起来非常奇怪。
那么问题是什么?
- 为什么在这个运行时大小的数组中没有出现指针衰减? - 用于确定运行时大小的数组大小的变量是运行时大小的数组类型的一部分,还是我误解了错误?

1
请注意,您在使用 int a[s]; 时使用了VLA扩展。 - Jarod42
很多编译器标志或代码规范禁止使用运行时大小的数组。(例如,我知道G++使用警告标志禁止它)你的编译器可能会拒绝将其用作模板。 - Aracthor
5
延伸Jarod42的评论,运行时大小的数组曾被提议,但最终未包含在C++14标准中。 - eerorika
我的错!我真的以为运行时大小的数组包含在C++14中(这就是为什么我添加了C++14标签)。无论如何,这并不改变问题:为什么在这个例子中VLA不会衰减为指针? - PaperBirdMaster
对于指针的衰减,您需要将参数类型设置为T*,而不是T*&。后者仅适用于实际指针。 - interjay
显示剩余3条评论
1个回答

3
在模板参数推导期间,仅当函数模板参数类型不是引用类型时,才使用数组到指针的转换。
§14.8.2.1 从函数调用中推导模板参数 [temp.deduct.call]
1、通过将每个函数模板参数类型(称为P)与调用的相应参数类型(称为A)进行比较来完成模板参数推导,具体如下所述。[...]
2、如果P不是引用类型:
- 如果A是一个数组类型,则使用由数组到指针的标准转换(4.2)生成的指针类型代替A进行类型推导; - 否则,[...]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接