[英]Why does sizeof operator fail to work inside function template?
I am trying to learn C++ function templates.I am passing an array as pointer to my function template. 我正在尝试学习C ++函数模板。我正在将数组作为指向函数模板的指针。 In that, I am trying to find the size of an array.
那样,我试图找到一个数组的大小。 Here is the function template that I use.
这是我使用的功能模板。
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;
}
The cout
statement displays the size of arr
as 1
even when I am passing the pointer to an array of 5
integers. 即使我将指针传递给
5
整数的数组, cout
语句arr
的大小显示为1
。 Now I know this might be a possible duplicate of questions to which I referred earlier but I need a better explanation on this. 现在我知道这可能是我先前提到的问题的可能重复,但是我需要对此进行更好的解释。
Only thing I could come up with is that since templates are invoked at runtime,and sizeof
is a compile time operator, compiler just ignores the line 我唯一能想到的是,由于模板是在运行时调用的,而
sizeof
是编译时的运算符,因此编译器只会忽略该行
int sz = sizeof(arr)/sizeof(arr[0]);
since it does not know the exact type of arr until it actually invokes the function. 因为它直到实际调用函数才知道arr的确切类型。 Is it correct or am I missing something over here?
是正确的还是我在这里错过了什么? Also is it reliable to send pointer to an array to the function templates?
将指向数组的指针发送到功能模板是否可靠?
T *arr
This is C++ for " arr
is a pointer to T
". 这是C ++的“
arr
是T
的指针”。 sizeof(arr)
obviously means "size of the pointer arr
", not "size of the array arr
", for obvious reasons. 由于明显的原因,
sizeof(arr)
显然意味着“指针arr
大小”,而不是“数组arr
大小”。 That's the crucial flaw in that plan. 那是该计划的关键缺陷。
To get the size of an array, the function needs to operate on arrays, obviously not on pointers. 为了获得数组的大小,该函数需要对数组进行操作,显然不能对指针进行操作。 As everyone knows (right?) arrays are not pointers.
众所周知(对吗?)数组不是指针。
Furthermore, an average function should return an average value. 此外,平均值函数应返回平均值。 But
T*
is a "pointer to T
". 但是
T*
是“指向T
指针”。 An average function should not return a pointer to a value. 平均值函数不应返回指向值的指针。 That is not a value.
那不是值。
Having a pointer return type is not the last offense: returning a pointer to a local variable is the worst of all . 拥有指针返回类型并不是最后的进攻:将指针返回到局部变量是最糟糕的 。 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;
}
If you want to be able to access the size of a passed parameter, you'd have to make that a template parameter, too: 如果要访问传递的参数的大小,则也必须使该模板参数:
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);
}
You can then omit the sizeof, obviously. 显然,您可以省略sizeof。 And you cannot accidentially pas a dynamically allocated array, which is a good thing.
而且您不能意外地通过动态分配数组,这是一件好事。 On the downside, the template will get instantiated not only once for every type, but once for every size.
不利的一面是,模板不仅针对每种类型实例化一次,而且针对每种尺寸实例化一次。 If you want to avoid duplicating the bulk of the code, you could use a second templated function which accepts pointer and length and returns the average.
如果要避免重复大量代码,则可以使用第二个模板化函数,该函数接受指针和长度并返回平均值。 That could get called from an inline function.
这可以从内联函数调用。
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);
}
Also note that returning the address of a variable which is local to the function is a very bad idea, as it will not outlive the function. 还要注意,返回函数本地变量的地址是一个非常糟糕的主意,因为它不会超出函数寿命。 So better to return a value and let the compiler take care of optimizing away unneccessary copying.
因此最好返回一个值,并让编译器负责优化不必要的复制。
Arrays decay to pointers when passed as a parameter, so you're effectively getting the size of the pointer. 作为参数传递时,数组会衰减到指针,因此您可以有效地获取指针的大小。 It has nothing to do with templates, it's how the language is designed.
它与模板无关,这是语言的设计方式。
Others have pointed out the immediate errors, but IMHO, there are two important points that they haven't addresses. 其他人指出了眼前的错误,但是恕我直言,他们还没有解决两个重要问题。 Both of which I would consider errors if they occurred in production code:
如果发生在生产代码中,我都会考虑这两种错误:
First, why aren't you using std::vector
? 首先,为什么不使用
std::vector
? For historical reasons, C style arrays are broken, and generally should be avoided. 由于历史原因,C样式数组已损坏,通常应避免使用。 There are exceptions, but they mostly involve static initialization of static variables.
也有例外,但它们大多涉及静态变量的静态初始化。 You should never pass C style arrays as a function argument, because they create the sort of problems you have encountered.
永远不要将C样式数组作为函数参数传递,因为它们会引起您遇到的问题。 (It's possible to write functions which can deal with both C style arrays and
std::vector
efficiently. The function should be a function template, however, which takes two iterators of the template type.) (可以编写可以高效处理C样式数组和
std::vector
的函数。但是,该函数应该是一个函数模板,但是需要两个模板类型的迭代器。)
The second is why aren't you using the functions in the standard library? 第二个原因是为什么不使用标准库中的函数? Your function can be written in basically one line:
您的函数基本上可以用一行编写:
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 );
}
(This function, of course, isn't reliable for floating point types, where rounding errors can make the results worthless. Floating point raises a whole set of additional issues. And it probably isn't really reliable for the integral types either, because of the risk of overflow. But these are more advanced issues.) (当然,此函数对于浮点类型并不可靠,因为舍入错误会使结果毫无价值。浮点引发了一系列其他问题。对于整数类型,它可能也不可靠,因为溢出的风险。但这是更高级的问题。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.