开发者问题收集

如何将向量或 valarray 作为参数传递给 C++ 模板函数

2021-12-13
401

我觉得这可能是一个基本问题,但经过一番搜索,我找不到简单的答案,所以我想问一下。

我有一个函数,用于返回容器中的第 n 个百分位值,但由于遗留原因,数组可以是向量或 valarray,并且可以包含双精度或浮点数。该函数的正确语法是什么? 目前我有:

template <template <class> class vType, class elType>
elType GetPercentile(vType<elType>& vData, double dPercentile)
{
    int iOffset = int(dPercentile * vData.size());
    std::nth_element(begin(vData), begin(vData) + iOffset, end(vData));
    return static_cast<elType>(vData[iOffset]);
}

传递 valarray 时编译成功,但传递向量时编译失败:

'elType GetPercentile(vType &,double)': could not deduce template argument for 'vType &' from 'std::vector<float,std::allocator>'

有办法吗?为两种容器类型复制代码似乎很愚蠢。(如果代码本身有任何评论,那也没问题。)

非常感谢您的任何建议。 Bill H

2个回答

您让模板变得过于复杂。只需这样做即可。无需静态转换。使用自动返回扣除。

另外,您可能不想通过引用传递 vData,因为 std::nth_element 将在部分排序过程中更改调用方的数据。此外, dPercentile 的命名不当,因为您没有将分数值按 100 缩放。请考虑缩放它或重命名该参数。

#include <vector>
#include <valarray>
#include <algorithm>

template<class vType>
auto GetPercentile(vType vData, double dPercentile)
{
    int iOffset = int(dPercentile * vData.size());
    std::nth_element(begin(vData), begin(vData) + iOffset, end(vData));
    return vData[iOffset];
}

int main()
{
    std::vector<float> v{ 1,2,3,4 };
    std::valarray<float> va{ 1., 2., 3., 4. };
    auto nth_v = GetPercentile(v, .5);   //returns 3.f
    auto nth_va = GetPercentile(va, .5); //returns 3.f
};
doug
2021-12-13

std::vector 有 2 个模板参数。第二个是分配器,它有一个默认值,因此您通常不会使用它。

但是,在 c++17 之前,模板模板参数仅在模板参数数量相同时才会匹配。在 c++17 中,这稍微放宽了一点,只要其余模板参数具有默认参数,就可以匹配具有更多模板参数的模板。

无论如何,我都会提出一种在两个容器中使用成员类型的解决方案,即 value_type

#include <vector>
#include <algorithm>
#include <valarray>

template <class T>
auto GetPercentile(T& vData, double dPercentile)
{
    using elType = typename T::value_type;
    int iOffset = int(dPercentile * vData.size());
    std::nth_element(begin(vData), begin(vData) + iOffset, end(vData));
    return static_cast<elType>(vData[iOffset]);
}

int main() {
    auto v = std::vector<int>{1,2,3,4,5};
    GetPercentile(v, 2);

    auto a = std::valarray<int>(5, 5);
    GetPercentile(a, 2);
}
super
2021-12-13