이것만은 잊지 말자!

- std::swap이 여러분의 타입에 대해 느리게 동작할 여지가 있다면 swap 멤버 함수를 제공
    - 이 멤버 swap은 예외를 던지지 않도록 만들자
    
- 멤버 swap을 제공한다면 멤버를 호출하는 비멤버 swap도 제공하자.
    - 템플릿이 아닌 클래스에 대해서는 std::swap도 특수화하자
    
- 사용자 입장에서 swap을 호출할 때 std::swap에 대한 using 선언을 넣어 준 후에 네임스페이스 한정 없이 swap을 호출

- 사용자 정의 타입에 대한 std 템플릿을 완전 특수화하는 것은 가능
    - std에 어떤 것이라도 새로 추가하지 말자

// 표준 swap
// 복사만 제대로 지원하는 타입이면 가능
// 복사 3번이 일어남
namespace std {
    template<typename T>
    void swap(T& a, T& b)
    {
        T temp(a);
        a = b;
        b = temp;
    }
}

// pImpl 관용구와 비슷하다면 표준 swap 효율이 안좋음
// 특수화 템플릿을 사용하지 않으면 Widget과 WidgetImp1 포인터를 복사
// private 멤버에 접근하기 위해 특수화 함수를 프렌드로 선언하면 표준 템플릿 규칙에 어긋남
// 기존 STL 컨테이너와 일관성 유지
class WidgetImp1
{
priavte:
    int a, b, c;
};

class Widget
{
public:
    void swap(Widget& other)
    {
        swap(pImp1, other.pImp1);
    }

private:
    WidgetImp1* pImp1;
};

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

// 클래스 템플릿에 대한 Swap
template<typename T>
class WidgetImp1 { ... };

template<typename T>
class Wdiget { ... };

// c++은 부분 특수화를 클래스 템플릿에 허용, 함수 템플릿에 허용 x => 컴파일 x
namespace std
{
    template<typename T>
    void swap<Widget<T>>(Widget<T>& a, Widget<T>& b)
    {
        a.swap(b);
    }
}

// 함수 템플릿을 부분 특수화 하고 싶을 때는 오버로드를 이용
// std의 템플릿에 대한 완전 특수화는 가능하지만 새로운 템플릿을 추가하는 것을 불가능
// 컴파일은 되지만 결과가 미정의 동작
// 따라서 std가 아닌 namespace 사용
// 컴파일러는 이름 탐색 규칙에 의해 Widget 네임스페이스 버전을 찾음
namespace Widget
{
	template<typename T>
	void swap(Widget<T>& a, Widget<T>& b)
	{
		a.swap(b);
	}
}

// 사용자 측면
template<typename T>
void doSomething(T& obj1, T& obj2)
{
	using std::swap; // std::swap를 이 함수 안으로 끌어옴
	swap(obj1, obj2); // 이름 탐색 규칙에 의해 T 전용 버전을 못 찾으면 std::swap을 사용

	// std의 swap을 사용, std가 아닌 네임스페이스 T 전용 swap 사용 불가
	// 완전 특수화가 중요한 이유가 이렇게 한정자를 붙여도 특수화 템플릿 사용 가능
	std::swap(obj1, obj2);
}

 

클래스 타입 전용의 swap이 많은 곳에서 호출하고 싶다면 네임스페이스 안의 비멤버 함수 사용

 

멤버 버전의 swap은 절대로 예외를 던지지 말자

  • 클래스 및 클래스 템플릿이 강력한 예외 안전성 보장을 제공하도록 하는 방법이 따로 있음(항목 29)
  • 비멤버의 경우 표준 swap에 사용되는 복사 생성 및 복사 대입 함수는 예외 발생 허용이 되므로 예외

이름 탐색 규칙(ADL, Argument Dependent Lookup, 인자 기반 탐색, 쾨니그 탐색)

  • 어떤 함수에 어떤 타입의 인자가 있으면 그 함수의 이름을 찾기 위해 해당 타입의 인자가 위치한 네임스페이스 내부의이름을 탐색해 들어간다는 간단한 규칙

+ Recent posts

목차