std:: qualifier needed when overloaded namespace function exists?

283 views Asked by At

If I have a little bit of code like:

using namespace std;

namespace myNamespace
{
    vector<float> sqrt( vector<float> v ) { return v; }

    void func()
    {
        vector<float> myVec = { 1, 2, 3, 4 };
        std::cout << sqrt( myVec )[0] << std::endl;
        float myFloat = 4.0f;
        std::cout << sqrt( myFloat ) << std::endl; // need to use std::sqrt()
    }
}

then it won't compile unless I changed the marked line to use std::sqrt. Why? I understand that if I tried to redefine sqrt(float) in myNamespace then I'd have to qualify with std:: if I wanted the standard library version to be used. The compiler appears to try to convert myFloat rather than just use a function in another (std) namespace.

One way I found to get around this is to define sqrt(vector<float>) in the std namespace but that doesn't quite feel right and answers to this question suggest overloading in std is illegal. Probably not the way to go then...

How can I overload sqrt (or any other standard library cmath function, for that matter) so that I don't have to always qualify which one to use and have the compiler select based on the passed function parameters?

Thanks.

2

There are 2 answers

2
quantdev On BEST ANSWER

In C++, name lookup doesn't care about parameters type, only the name matters. When the compiler looks for a function named sqrt, it will always find your version first (since the lookup starts with the enclosing namespace), and stops there.

You must help the compiler by bringing the name from std:: into scope with a using directive in your namespace :

namespace myNamespace
{
  using std::sqrt
  ...
}

Then, standard overload resolution will take place to distinguish between your sqrt and std::sqrt, and will select the correct sqrt function to be called.

To avoid any ambiguity, you should always qualify the name (std::sqrt or myNamespace::sqrt)


Notes:

  • As pointed out by Simple, Argument Dependent Lookup (ADL) makes std::sqrt available for name lookup in the first case (since vector is in std::), but it doesn't change the problem you're facing.

  • Declaring your own sqrt function in std:: is a very bad idea (forbidden by the standard, except for template specializations)

0
Bathsheba On

You can bring std::sqrt into your namespace via the statement using std::sqrt; within myNamespace:

namespace myNamespace
{
    vector<float> sqrt( vector<float> v ) { return v; }
    using std::sqrt;
    ...

Then the compiler will pick the appropriate sqrt in std::cout << sqrt( myFloat )