用户定义的类型不可能重载swap。namespace std引入重载(与专业化相反)namespace std是未定义的行为(根据标准是非法的,不需要诊断)。
不可能为一个template类专门化一个函数(与template类实例相反——即,std::vector<int>是一个实例,std::vector<T>而是整个template类)。看似专业化的东西实际上是一种超载。所以第一段适用。
实现用户定义的最佳实践是在与您的或生活相同的命名空间中swap引入函数或重载。swaptemplateclass
然后,如果swap在正确的上下文 ( using std::swap; swap(a,b);) 中调用它,这就是它在std库中的调用方式,ADL 将启动,并且将找到您的重载。
另一种选择是对您的特定类型进行完全swap专业化std。这对于类来说是不可能的(或不切实际的) ,因为您需要专门针对存在的类template的每个实例。template对于其他类,它是脆弱的,因为专门化仅适用于该特定类型:子类也必须重新专门化std。
一般来说,函数的特化是非常脆弱的,最好引入覆盖。由于您无法将覆盖引入std其中,因此可以可靠地找到它们的唯一位置是您自己的namespace. 您自己的命名空间中的此类覆盖也比 in 中的覆盖更std受欢迎。
有两种方法可以将 aswap注入您的命名空间。两者都为此目的工作:
namespace test {
struct A {};
struct B {};
void swap(A&, A&) { std::cout << "swap(A&,A&)\n"; }
struct C {
friend void swap(C&, C&) { std::cout << "swap(C&, C&)\n"; }
};
void bob() {
using std::swap;
test::A a, b;
swap(a,b);
test::B x, y;
swap(x, y);
C u, v;
swap(u, v);
}
}
void foo() {
using std::swap;
test::A a, b;
swap(a,b);
test::B x, y;
swap(x, y);
test::C u, v;
swap(u, v);
test::bob();
}
int main() {
foo();
return 0;
}
第一个是将其直接注入namespace,第二个是将其包含为 inline friend。“外部运算符”的内联friend是一种常见模式,基本上意味着您只能swap通过 ADL 找到,但在这个特定的上下文中并没有增加太多。