我对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 的另一种数据类型?
答案 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样式数组和