-1

我正在尝试学习 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语句也会显示arras的大小。现在我知道这可能与我之前提到的问题重复,但我需要对此进行更好的解释。15

我唯一能想到的是,由于模板是在运行时调用的,并且sizeof是一个编译时运算符,编译器只是忽略该行

   int sz = sizeof(arr)/sizeof(arr[0]);

因为它在实际调用函数之前不知道 arr 的确切类型。这是正确的还是我在这里遗漏了什么?将指向数组的指针发送到函数模板是否可靠?

4

4 回答 4

6
 T *arr

这是 C++,因为“arr 是指向T”的指针。sizeof(arr)显然是指“指针的大小arr”,而不是“数组的大小arr”,原因很明显。这是该计划的关键缺陷。

要获得数组的大小,函数需要对数组进行操作,显然不是指针。众所周知(对吗?)数组不是指针。

此外,平均函数应该返回一个平均值。而是T*一个“指针T”。平均函数不应返回指向值的指针。那不是一个值。

有一个指针返回类型并不是最后的攻击:返回一个指向局部变量的指针是最糟糕的你为什么要偷酒店房间钥匙?

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;
}
于 2012-06-28T06:51:03.030 回答
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);
}

另请注意,返回函数本地变量的地址是一个非常糟糕的主意,因为它不会超过函数。所以最好返回一个值并让编译器负责优化不必要的复制。

于 2012-06-28T06:56:13.370 回答
3

数组作为参数传递时会衰减为指针,因此您可以有效地获取指针的大小。它与模板无关,它是语言的设计方式。

于 2012-06-28T06:48:27.060 回答
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 );
}

(当然,这个函数对于浮点类型是不可靠的,因为舍入错误会使结果变得毫无价值。浮点会引发一整套额外的问题。而且它对于整数类型也可能并不可靠,因为溢出的风险。但这些是更高级的问题。)

于 2012-06-28T07:41:18.510 回答