5

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.

Community
  • 1
  • 1
user2746401
  • 3,157
  • 2
  • 21
  • 46
  • 1
    Declaring your own function in the `std` namespace is definitely wrong. You *could* declare it in the global namespace, since you've dumped `std` in there for some reason. Or you could add `using std::sqrt;` to your namespace, alongside your `sqrt`. I'd just qualify the name properly. – Mike Seymour Nov 19 '14 at 15:20
  • 1
    You could also just not use use `using namespace somethingsomething` and always use the std:: prefix, avoiding crap like this altogether. – Cubic Nov 19 '14 at 16:09

2 Answers2

9

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)

quantdev
  • 23,517
  • 5
  • 55
  • 88
  • Is there a way to bring all std:: names into the current namespace? Something like using std::*? – user2746401 Nov 19 '14 at 15:30
  • 2
    It does care about the parameter types though. In the first call to `sqrt` the compiler will have found both `myNamespace::sqrt` and `std::sqrt` via ADL (because `vector` is in `std`). It only chooses `myNamespace::sqrt` because it's a better match. – Simple Nov 19 '14 at 15:32
3

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 )

Bathsheba
  • 231,907
  • 34
  • 361
  • 483