0

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

主文件

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()中的数组不同的数据类型?

4

2 回答 2

6

实际上,当您将数组传递给函数时,它会衰减为指针类型。所以T推断为int*,而不是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++ 中,数组(和函数)不能按值传递。语言不允许这样做。相反,当它们作为函数参数传递时,语言要求它们衰减为指针类型。为了防止衰减,我们需要将它们作为参考传递。

于 2013-02-26T09:44:47.170 回答
3

因为 C 风格的数组被破坏了。特别是,你不能有一个 C 风格数组类型的函数参数。如果您编写一个函数(暂时忘记模板):

void foo( int arg[100] );

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

void foo( int* arg );

(并且 the100只是一个注释——编译器会忽略它)。

为了在模板的情况下支持这一点,如果编译器试图匹配非引用模板参数,它会将数组参数转换为指针,类型推导将导致指针类型,而不是数组类型。

结果是您永远不应该编写一个期望 C 样式数组的函数(模板或其他)(除了 的第二个参数main,您别无选择)。

由于这种中断仅出于 C 兼容性的原因而存在,因此在涉及引用时 C++ 不会遵循它。所以:

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

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

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

于 2013-02-26T10:04:32.153 回答