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

时间:2012-06-28 06:46:38

标签: c++ templates sizeof

我正在尝试学习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的确切类型。 这是正确的还是我错过了这里的东西?将指针发送到函数模板也是可靠的吗?

4 个答案:

答案 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 );
}

(当然,对于浮点类型,此函数不可靠, 舍入错误可以使结果毫无价值。浮点 提出了一整套其他问题。它可能不是真的 由于存在溢出的风险,因此对于积分类型也是可靠的。 但这些是更高级的问题。)