《Effective C++》条款25

考虑写出一个不抛异常的swap函数

存在这样两个类:

class A
{
public:
	...
private:
	int a, b, c;
	std::vector v;
};
class B
{
public:
	...
private:
	A* aptr;
};

如果想调用std::swap去置换B对象,那么我们想做的就是置换其A指针,但是缺省的swap函数并不知道。它不只复制了三个B类对象,还复制了三个A类对象,非常影响效率!

所以我们需要将std::swap进行特化: 

namespace std
{
	template<>
	void swap(B& a, B& b)
	{
		swap(a.aptr, b.aptr);
	}
}

思路是对的,但是这样写会报错,因为访问到了私有变量。

改成这样就行了:

class B
{
public:
	//...
	void swap(B& a)
	{
		using std::swap;
		swap(aptr, a.aptr);
	}
private:
	A* aptr;
};
namespace std // 与std内的swap本质上构成函数重载
{
	template<>
	void swap(B& a, B& b)
	{
		a.swap(b);
	}
}

这种做法不仅能通过编译,还与STL容器有一致性,因为所有的STL容器也都是供有public swap成员函数和std::swap特化版本(用以调用前者)

但是你想进行偏特化,结果是行不通的。

namespace std
{
	template
	void swap>(B& a, B& b)
	{
		a.swap(b); // 报错
	}
}

因为C++只允许对class template偏特化,对function template是行不通的。不能通过编译

一般而言写成重载版本会解决这个问题:

namespace std
{
	template
	void swap(B& a, B& b)
	{
		a.swap(b);
	}
}

但是问题又来了:因为std是个特殊的命名空间。客户可以全特化std内的templates,但是不可以添加新的templates进去。

 如何解决?

将它们写入同一个命名空间内。并且用non-member函数调用member函数。

namespace test
{
	...
	template
	class B
	{
		void swap(B& a)
		{
			using std::swap;
			swap(aptr, a.aptr);
		}
		...
	};
	template
	void swap(B& a, B& b)
	{
		a.swap(b);
	}
}

你可能感兴趣的:(c++)