我正在尝试学习C ++函数模板。我传递一个数组作为指向我的函数模板的指针。在那,我试图找到一个数组的大小。这是我使用的功能模板。
template<typename T>
T* average( T *arr)
{
T *ansPtr,ans,sum = 0.0;
size_t sz = sizeof(arr)/sizeof(arr[0]);
cout<<"\nSz is "<<sz<<endl;
for(int i = 0;i < sz; i++)
{
sum = sum + arr[i];
}
ans = (sum/sz);
ansPtr = &ans;
return ansPtr;
}
即使我将指针传递给cout
整数数组,arr
语句也会将1
的大小显示为5
。现在我知道这可能是我之前提到的问题的可能重复,但我需要对此有更好的解释。
我唯一能想到的是,因为模板是在运行时调用的,sizeof
是编译时操作符,编译器只是忽略了行
int sz = sizeof(arr)/sizeof(arr[0]);
因为在实际调用函数之前它不知道arr的确切类型。 这是正确的还是我错过了这里的东西?将指针发送到函数模板也是可靠的吗?
答案 0 :(得分:6)
T *arr
这是C ++,“arr
是指向T
”的指针。 sizeof(arr)
显然意味着“指针arr
的大小”,而不是“数组arr
的大小”,原因显而易见。这是该计划中的关键缺陷。
要获得数组的大小,该函数需要对数组进行操作,显然不是在指针上。众所周知(对吗?)数组不是指针。
此外,平均函数应返回平均值。但T*
是“指向T
的指针”。平均函数不应返回指向值的指针。这不是一个价值。
指针返回类型不是最后一次攻击:返回指向本地变量的指针是最糟糕的。 Why would you want to steal hotel room keys?
template<typename T, std::size_t sz>
T average( T(&arr)[sz])
{
T ans,sum = 0.0;
cout<<"\nSz is "<<sz<<endl;
for(int i = 0;i < sz; i++)
{
sum = sum + arr[i];
}
ans = (sum/sz);
return ans;
}
答案 1 :(得分:4)
如果您希望能够访问传递参数的大小,您还必须使其成为模板参数:
template<typename T, size_t Len>
T average(const T (&arr)[Len])
{
T sum = T();
cout<<"\nSz is "<<Len<<endl;
for(int i = 0;i < Len; i++)
{
sum = sum + arr[i];
}
return (sum/Len);
}
然后你可以省略sizeof。并且你不能意外地通过一个动态分配的数组,这是一件好事。在缺点方面,模板不仅会针对每种类型实例化一次,而是针对每种尺寸实例化一次。如果要避免重复大量代码,可以使用第二个模板化函数接受指针和长度并返回平均值。这可以从内联函数调用。
template<typename T>
T average(const T* arr, size_t len)
{
T sum = T();
cout<<"\nSz is "<<len<<endl;
for(int i = 0;i < len; i++)
{
sum = sum + arr[i];
}
return (sum/len);
}
template<typename T, size_t Len>
inline T average(const T (&arr)[Len])
{
return average(arr, Len);
}
另请注意,返回函数本地变量的地址是一个非常坏主意,因为它不会比该函数寿命更长。因此,最好返回一个值,让编译器负责优化不必要的复制。
答案 2 :(得分:3)
当作为参数传递时,数组会衰减为指针,因此您可以有效地获取指针的大小。它与模板无关,而是语言的设计方式。
答案 3 :(得分:1)
首先,您为什么不使用std::vector
?由于历史原因,C
样式数组被破坏,通常应该避免。有
异常,但它们主要涉及静态的静态初始化
变量。您应该永远将C样式数组作为函数传递
争论,因为他们创造了你遇到的那种问题。
(可以编写可以处理C风格的函数
数组和 std::vector
有效。该功能应该是一个
但是,函数模板需要两个模板迭代器
类型。)
第二个是你为什么不使用标准中的功能 图书馆?您的功能基本上可以写成一行:
template <typename ForwardIterator>
typename ForwardIterator::value_type
average( ForwardIterator begin, ForwardIterator end )
{
return std::accumulate( begin, end,
typename::ForwardIterator::value_type() )
/ std::distance( begin, end );
}
(当然,对于浮点类型,此函数不可靠, 舍入错误可以使结果毫无价值。浮点 提出了一整套其他问题。它可能不是真的 由于存在溢出的风险,因此对于积分类型也是可靠的。 但这些是更高级的问题。)