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

How to pass a vector or a valarray as an argument to a C++ template function

我觉得这可能是一个初级问题,但经过大量搜索后找不到简单的答案,所以我想问一下。

我有一个函数旨在 return 容器中的第 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>'

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

非常感谢您的任何建议。 比尔·H

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

您使模板过于复杂。就这样做吧。无需静态投射。使用自动 return 扣除。

顺便说一句,您可能不想通过引用传递 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
};