1

I want to use std::sort, but the compile is failing with error C2668: std::swap: ambiguous call to overloaded function because there is a templated swap() function defined in my namespace that would be hard to get rid of. I don't care which swap it uses, but how do I make either one of them go away when compiling sort()?

I understand that it's ambiguous because my::swap is in the same namespace as my::Obj, and I don't care which version of swap gets used. I just have to overcome the namespace collision. This is part of a very large code base that I don't own so I'm hoping for a solution that is local to my code and presumably allows my::Obj and my::swapto both stay in namespace my.

namespace my
{
    template<class T> void swap(T a, T b)
    {
    }

    struct Obj
    {
    };

    void doSortStuff()
    {
        std::vector<Obj> arr;
        std::sort(arr.begin(), arr.end());
    }
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
All The Rage
  • 743
  • 5
  • 24
  • Possible duplicate of [Why is this call to swap() ambiguous?](https://stackoverflow.com/questions/34075718/why-is-this-call-to-swap-ambiguous) – Valrog Oct 25 '18 at 22:08
  • 2
    Why not put your templated swap in its own namespace and then call it using that namespace? – Bilal Saleem Oct 25 '18 at 22:09
  • 2
    are you `using namespace std`? – Sailanarmo Oct 25 '18 at 22:09
  • @BilalSaleem Probably because the call is inside `std::sort`. – juanchopanza Oct 25 '18 at 22:14
  • 2
    See this example answer to a similar post: https://stackoverflow.com/a/51165683/2785528 Which explains 2 options. You can move your code, as simply as possible, into a 'distinguishing' namespace. Or, you can move your code into a 'distinguishing' class. Either will end the ambiguity. Of course, without more info on your code ... well, you really should provide a [MCVE] – 2785528 Oct 25 '18 at 22:16

3 Answers3

2

A workaround is to create a better overload:

// No modifiable code
namespace my
{
    template<class T> void swap(T a, T b) { /*.. */ }
    struct Obj { /*..*/ };
}

// Your code:
namespace my
{
    void swap(Obj& lhs, Obj& rhs)
    {
        // my::swap<Obj&>(lhs, rhs);
        std::swap(lhs, rhs);
    }
}

// In namespace you want.
void doSortStuff()
{
    std::vector<my::Obj> arr;
    std::sort(arr.begin(), arr.end());
}

Then, between the 3 valid overloads, all are exact match, but the non-template is preferred.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
2

Contrary to some comments and surprising to some this error happens without using namespace std. Here is a minimal example to understand what is going on:

namespace like_std
{
    template<class T> void swap(T a, T b) {}

    template <class T> auto test(T x, T y)
    {
        swap(x, y); // (1) ambiguous call
    }
}

namespace my
{
    template<class T> void swap(T a, T b) {}

    struct Obj {};

    void doStuff()
    {
        like_std::test(Obj{}, Obj{});
    }
};

You do a call to a function from like_std and inside this function there is an unqualified call to swap. For this call:

  • like_std::swap is a candidate because is in the same namespace as the call to swap

  • my::swap is a candidate because of ADL: it's brought in because it's in the same namespace as one of the arguments to the call of swap

Since neither of those is better there is an ambiguity.

The reason why the call to swap is unqualified is so that it will pick up a custom swap if it's defined, but that works only if the custom swap is a better candidate, which is assumed for a custom swap function.

The solution, as Jarod42 showed is to define a better candidate swap function.

bolov
  • 72,283
  • 15
  • 145
  • 224
-1

You are probably using namespace std;.

In this case, the compiler does not know what to choose as it makes all std:: members available without typing it automatically, where both functions are suitable:

using namespace std;
swap(a, b); //your swap
swap(a, b); //std::swap

As in this case, you have strict function calls:

std::swap(a, b); //from std
swap(a, b); // your one

This is actually a very good example of why you should avoid using namespace std. Good luck!

Update: This can be your solution - move your swap() outside of std::sort() usage:

#include <algorithm>
#include <vector>

namespace detail
{
  struct someContainer
  {
    someContainer(int &v)
    {
      value = v;
    }
    int value;
    someContainer &operator = (const someContainer & rhs)
    {
      this->value = rhs.value;
    }
    bool operator == (someContainer &rhs) const
    {
      return this->value == rhs.value;
    }
    bool operator <= (someContainer &rhs) const
    {
      return this->value <= rhs.value;
    }
    bool operator >= (someContainer &rhs) const
    {
      return this->value >= rhs.value;
    }
    bool operator > (someContainer &rhs) cosnt
    {
      return this->value > rhs.value;
    }
    bool operator < (someContainer &rhs) const
    {
      return this->value < rhs.value;
    }
  };
  void doSomeStuff()
  {
    std::vector<someContainer> vec;
    for (int i = 0; i < vec.size(); ++i)
    {
      vec.push_back(someContainer(i));
    }
    std::sort(vec.begin(), vec.end());
  }
}

namespace mySwap
{
  template< class T >
  void swap(T &a, T &b)
  {
     T c = a;
     a = b;
     b = c;
  }
}
int main()
{
  detail::doSomeStuff();
  return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Max Vlasov
  • 118
  • 2
  • 9
  • Thanks. I'm not using namespace std, though. But the code calling std::sort is in the same namespace as the other version of swap. I can see why they're both pulled in, but what's the most elegant way to express which one I want? – All The Rage Oct 25 '18 at 23:06
  • 1
    @AlltheRage I think that the easiest way is not to use your custom swap as standard one already exists. Why would you ever need that? But you also can move you swap to another namespace where std::sort() is not called. – Max Vlasov Oct 25 '18 at 23:36
  • Thanks. This is part of a big code base that I don't own. I only control a small piece. They wrote the whole thing without using STL, which is why they have their own swap. If I can't modify their swap, do you have any other ideas? – All The Rage Oct 25 '18 at 23:47
  • 1
    @AlltheRage then, I think, the only idea is to implement your own sort() which is quicksort algorithm in C++ – Max Vlasov Oct 25 '18 at 23:50
  • the error appears even without `using namespace std` because of ADL – bolov Oct 26 '18 at 00:20
  • @bolov I told about possible `using namespace std` problem before he exampled the code, so I updated it then – Max Vlasov Oct 26 '18 at 09:22