简体   繁体   English

为什么sizeof运算符无法在函数模板中工作?

[英]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 ++的“ arrT的指针”。 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.

相关问题 为什么 sizeof(ar)/sizeof(ar[0]) 在传递给函数时不能在向量上正常工作? - Why does sizeof(ar)/ sizeof(ar[0]) not work properly on a vector when passed to a function? 为什么MSVC无法编译此模板函数? - Why does MSVC fail to compile this template function? 为什么sizeof ...不能使用此别名模板? - Why doesn't sizeof… work with this alias template? 为什么在 C++ 中使用关系运算符制作的模板函数对字符串不能正常工作? - Why does a Template function made using relational operator in C++ not work correctly for strings? 为什么在函数参数中使用赋值运算符会失败? - Why does this use of assignment operator in a function argument fail? 在可变参数模板中使用sizeof运算符可在递归结束时跳过该函数 - Use of sizeof operator in Variadic Template to skip the function for the end of recursion 为什么此函数指针的可变参数模板参数推导失败? - Why does the variadic template argument deduction fail for this function pointer? 模板中的朋友功能(为什么这在Visual Studio中失败但在GCC和Clang中失败) - Friend function in template (why does this fail in Visual Studio but not GCC and Clang) 为什么模板参数推导因重载函数而失败? - Why does template argument deduction fail with overloaded function? 为什么 sizeof 运算符对数组产生不同的结果 - Why does the sizeof operator produce different results for an array
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM