Home > front end >  putting function inside a namespace breaks use of std::vector
putting function inside a namespace breaks use of std::vector

Time:03-25

I have written a function that does the element-wise square root of a std::vector<double>

#include <cmath>
#include <vector>
namespace pcif {
    std::vector<double> sqrt(const std::vector<double>& d) {
        std::vector<double> r;
        r.reserve(d.size());
        for (size_t i{ 0 }; i < r.size();   i) {
            r.push_back(sqrt(d[i]));
        }
        return r;
    }
}

I am getting the error (all pointing to the r.push_back line):

  • cannot convert from 'const _Ty' to 'const std::vector<double,std::allocator>'
  • error C2664: 'std::vector<double,std::allocator> pcif::sqrt(const std::vector<double,std::allocator> &)': cannot convert argument 1 from 'const _Ty' to 'const std::vector<double,std::allocator> &'
  • Constructor for class 'std::vector<double,std::allocator>' is declared 'explicit'

If I remove the namespace, it all compiles with no dramas.

What am I doing wrong? Is there a better way to do this?

I am working in Visual Studio 2019, C 17.

.

Follow-up question:

Using the fully qualified std::sqrt() solves this. Why did it work in my original case with no namespace? I can't just call vector<double>, why can I call sqrt?

CodePudding user response:

As already mentioned in comments, you should explicitly call ::sqrt() (or from std namespace, std::sqrt()) instead, otherwise you are recursively calling your own sqrt() function with the wrong arguments.

The reason is that in the global namespace, there already exists a matching function called sqrt() (that's why it worked outside of the pcif namespace).
Once you are inside the pcif namespace, there are no other sqrt() overloads defined except the one you are writing, hence the recursion with the wrong arguments (Overloads are looked up in the same scope).
To solve this, you can explicitly call either the function of the global namespace ::sqrt() or the one defined in the std namespace std::sqrt().

Moreover, you should also change your loop condition from i < r.size() to i < d.size() instead, since r is empty. Keep in mind that reserve(n) does not change the size of the container, it only allocates the necessary space for being able to store at least n elements without the need of reallocations (i.e. only the capacity is changed).
You may be interested to have a look at the documentation.

CodePudding user response:

The problem is that due to overload resolution, in the call expression sqrt(d[i]), the name sqrt refers to the same function that you're in. And since the type of the argument d[i] doesn't match with the type of the parameter d of the custom defined function, you get the mentioned error.

To solve this, you can qualify the name sqrt with std:: in the call expression sqrt(d[i]) so that it looks like:

namespace pcif {
    std::vector<double> sqrt(const std::vector<double>& d) {
        std::vector<double> r;
        r.reserve(d.size());
        for (size_t i{ 0 }; i < d.size();   i) {
//----------------------vvv--------------------> std:: added here
            r.push_back(std::sqrt(d[i]));
        }
        return r;
    }
}

By using std:: we're saying to the compiler that look in the std namespace for a function named sqrt.

  • Related