如何使 std::sort 在 std::swap 和我的名称空间模板交换之间没有名称冲突?
How do I make std::sort not have name collision between std::swap and my namespace's templated swap?
我想使用 std::sort
,但编译失败并出现错误 C2668: std::swap: ambiguous call to overloaded function
,因为在我的命名空间中定义了一个模板化的 swap()
函数,该函数很难删除.我不关心它使用哪个 swap
,但是如何在编译 sort()
时让它们中的任何一个消失?
我知道这是不明确的,因为 my::swap
与 my::Obj
在同一个命名空间中,我不关心使用哪个版本的 swap
。我只需要克服名称空间冲突。这是我不拥有的非常大的代码库的一部分,所以我希望有一个适合我的代码的解决方案,并且大概允许 my::Obj
和 my::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());
}
};
你大概是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;
}
解决方法是创建更好的重载:
// 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
函数。
如 所示,解决方案是定义一个更好的候选 swap
函数。
我想使用 std::sort
,但编译失败并出现错误 C2668: std::swap: ambiguous call to overloaded function
,因为在我的命名空间中定义了一个模板化的 swap()
函数,该函数很难删除.我不关心它使用哪个 swap
,但是如何在编译 sort()
时让它们中的任何一个消失?
我知道这是不明确的,因为 my::swap
与 my::Obj
在同一个命名空间中,我不关心使用哪个版本的 swap
。我只需要克服名称空间冲突。这是我不拥有的非常大的代码库的一部分,所以我希望有一个适合我的代码的解决方案,并且大概允许 my::Obj
和 my::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());
}
};
你大概是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;
}
解决方法是创建更好的重载:
// 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
函数。
如 swap
函数。