c++vectormigrationc++20valarray

how to pass valarray or vector as argument in C++20


I want a function that can take either a valarray or vector as an argument. The (trivial sample) code below works fine in C++17 (compiles, runs, and gives the right answer), but fails to compile in C++20 with the error message

'GetSum': no matching overloaded function found

It works if I call the pointer version directly, but it's obviously neater if I can just pass the container.

template<class T>
T GetSum(std::valarray<T>& vIn)
{
    return GetSum(&vIn[0], vIn.size());
}

template<class T>
T GetSum(std::vector<T>& vIn)
{
    return GetSum(&vIn[0], vIn.size());  // could use .data() here
}

// pointer version
template<class T>
T GetSum(T* vIn, size_t n)
{
    T sum{};
    for (size_t i = 0; i < n; ++i)
        sum += vIn[i];
    return sum;
}


void OnTest()
{
    std::vector<double> vec(10, 1);
    std::valarray<int> val(3, 10);

    double x = GetSum(vec);
    int i = GetSum(val);
...

Sorry for my ignorance, but can someone tell me what I am doing wrong? (FYI I asked a question on this topic a while back, which was how I got the C++17 code working OK, but now I'm trying to move to C++20 and find that my code no longer works).


Solution

  • can someone tell me what I am doing wrong?

    The problem is that you're trying to call the pointer version of GetSum before declaring it. In other words, when you wrote GetSum(&vIn[0], vIn.size()) the compiler can't find the suitable version because name lookup only considers declaration at or before that point.

    To solve this, you can move its declaration before using/calling it as shown below:

    //first declare/define this
    template<class T>
    T GetSum(T* vIn, size_t n)
    {
        T sum{};
        for (size_t i = 0; i < n; ++i)
            sum += vIn[i];
        return sum;
    }
    
    //now you can use the above
    template<class T>
    T GetSum(std::vector<T>& vIn)
    {
        //now this'll work because we've already declared the pointer version above
        return GetSum(&vIn[0], vIn.size());  
    }
    
    template<class T>
    T GetSum(std::valarray<T>& vIn)
    {
        return GetSum(&vIn[0], vIn.size());
    }
    

    Working demo