如何使 std::sort 在 std::swap 和我的命名空间的模板化交换之间没有名称冲突?



我想使用std::sort,但编译失败并出现错误C2668: std::swap: ambiguous call to overloaded function,因为我的命名空间中定义了一个模板化的swap()函数,很难摆脱。我不在乎它使用哪swap,但是在编译sort()时如何让其中任何一个消失?

我知道这是模棱两可的,因为my::swapmy::Obj位于同一命名空间中,我不在乎使用哪个版本的swap。我只需要克服命名空间冲突。这是我不拥有的非常大的代码库的一部分,所以我希望有一个我的代码本地的解决方案,并且可能允许my::Objmy::swap都留在命名空间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());
}
};

解决方法是创建更好的重载:

// 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());
}

然后,在 3 个有效重载之间,所有重载都是完全匹配的,但模板是首选。

与某些评论相反,令某些人感到惊讶的是,此错误在没有using namespace std的情况下发生。下面是一个了解正在发生的事情的最小示例:

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{});
}
};

您从like_std调用函数,在此函数内部有一个对swap的非限定调用。对于此调用:

  • like_std::swap是候选对象,因为与调用swap位于同一命名空间中

  • my::swap是 ADL 的候选对象:引入它是因为它与调用swap的参数之一位于同一命名空间中

由于这两种情况都不好,因此存在歧义。

swap的调用是非限定的原因是,如果已定义,它将选取自定义swap但这仅在自定义swap是更好的候选项时才有效,这是自定义swap函数的假设。

正如Jarod42所示,解决方案是定义一个更好的候选函数swap

你可能using namespace std;.

在这种情况下,编译器不知道要选择什么,因为它使所有std::成员都可用,而无需自动键入它,其中两个函数都适用:

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

在这种情况下,您有严格的函数调用:

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

这实际上是一个很好的例子,说明为什么你应该避免using namespace std.祝你好运!

更新:这可以是您的解决方案 - 将您的swap()移出std::sort()使用:

#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;
}

最新更新