为什么类型推导不能按预期工作

why type deduction does not work as expected?

本文关键字:工作 不能按 类型 为什么      更新时间:2023-10-16

我有一个关于C++元编程中的类型推导的小问题。有一定的功能做一些动作。

main.cpp

template<typename T> void foo(T arg) {
    // do some action on argument
    std::cout << typeid(arg).name() << std::endl;
}

int main(int argc, char** argv) {
    int array[100] = {0};
    std::cout << typeid(array).name() << std::endl;
    foo(array);
    return 0;
}

输出:

A100_i
Pi     

为什么函数foo((中的arg与函数main((中数组有另一种数据类型

实际上,当您将数组传递给函数时,它会衰减为指针类型。因此推导出Tint*,而不是int[100]

如果要防止衰减,请通过引用接受参数。:

template<typename T> void foo(T & arg) //Note `&` here!
{
  // do some action on argument
   std::cout << (typeid(arg).name() << std::endl;
}

现在它将打印您期望的内容,即A100_i。请参阅此在线演示。


问题:当我们按值传递时,为什么数组会衰减为指针类型

答:因为在C++中,数组(和函数(不能通过值传递。语言不允许这样。相反,当它们作为函数参数传递时,该语言要求它们衰减为指针类型。为了防止衰变,我们需要将它们作为引用传递。

因为C风格的数组已损坏。特别是,你不能具有一个C风格数组类型的函数参数;如果你写一个函数(暂时忘记模板(:

void foo( int arg[100] );

该语言要求编译器将其视为:

void foo( int* arg );

(而100只是一个注释—它被编译器(。

为了在模板的情况下支持这一点,如果编译器正在尝试匹配非引用模板参数,它将把数组参数转换为指针,并键入推导将产生指针类型,而不是数组类型。

结果是,您永远不应该编写函数(模板或以其他方式(期望C样式数组(除了第二个main的自变量,在这里您别无选择(。

由于这种破碎只存在于C兼容性,当引用卷入的因此:

template < typename T, size_t N >
void foo( T (&arg)[ N ] );

会起作用,并且在两种情况下都会给您相同的结果。如果您认为您的函数可能同时调用C风格的数组和其他东西(例如std::vector(,您可以两者都超载。上面的版本更专业,并且如果可能的话将优选于更通用的版本。

更好的解决方案是完全避免使用C型数组,但是它们对于初始化的静态变量很有用;它是只有使用C风格的数组,才能让编译器计数元素的数量,并定义数组的大小根据初始值设定项列表。并具有静态初始化;std::vector将在运行时,但用作静态变量,可能会导致初始化问题。C型数组和