为什么类型扣除不能按预期工作?

时间:2013-02-26 09:42:55

标签: c++ metaprogramming type-deduction

我对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()中具有 array 的另一种数据类型?

2 个答案:

答案 0 :(得分: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。请参阅this online demo


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

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

答案 1 :(得分:3)

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

void foo( int arg[100] );

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

void foo( int* arg );

100只是一个评论 - 它被忽略了 编译器)。

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

结果是你永远不应该写一个函数(模板 或者)期待一个C风格的数组(第二个除外) main的参数,你没有选择的地方。)

因为这种破坏只是出于原因而存在 C兼容性,C ++在引用时不遵循它 参与其中。所以:

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

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

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