40

교과서 함수 오버로드에 대한 템플릿 전문화를 통해 swap(x,y)과 같은 표준 라이브러리 함수에 대한 사용자 고유의 구현을 제공 할 수 있다는 메모가 있습니다. 이는 예를 들어 STL containers과 같이 할당 스왑 이외의 다른 이점을 누릴 수있는 모든 유형에 유용합니다 (이미 스왑이 쓰여져 있음).템플릿 전문화 VS 함수 오버로드

내 질문은 :

  1. 더 나은 기능 : 템플릿 특수화하여 전문 스왑 구현을 제공하거나, 기능 템플릿없이 사용하고자하는 정확한 매개 변수를 제공하는 오버로드에?

  2. 왜 더 낫습니까? 또는 그들이 동등한 경우에, 왜 이것입니까?

답변

60

단편 : 필요할 때마다 할 수 있으면 과부하.

Long story : C++은 전문화와 과부하를 매우 다르게 처리합니다. 이것은 예제를 통해 가장 잘 설명됩니다.

template <typename T> void foo(T); 
template <typename T> void foo(T*); // overload of foo(T) 
template <>   void foo<int>(int*); // specialisation of foo(T*) 

foo(new int); // calls foo<int>(int*); 

이제 마지막 두 개를 바꾸어 봅시다.

template <typename T> void foo(T); 
template <>   void foo<int*>(int*); // specialisation of foo(T) 
template <typename T> void foo(T*); // overload of foo(T) 

foo(new int); // calls foo(T*) !!! 

컴파일러는 전문화하기 전에 해상도를 오버로드합니다. 따라서 두 가지 경우 모두 과부하 해결은 foo(T*)을 선택합니다. 그러나 두 번째 경우 int* 전문화 과정은 foo(T)이 아닌 foo(T*)의 전문화이기 때문에 첫 번째 경우에만 foo<int*>(int*)을 찾습니다.


귀하는 std::swap을 언급했습니다. 이것은 일을 훨씬 더 복잡하게 만듭니다.

표준은 std 네임 스페이스에 전문화를 추가 할 수 있다고 말합니다. 좋아요, 당신은 Foo 타입을 가지고 있고 퍼포먼스 스왑을 가지고 있습니다. 그러면 네임 스페이스에 swap(Foo&, Foo&)을 전문으로합니다. 아무 문제 없습니다.

하지만 Foo이 템플릿 클래스 인 경우 어떻게해야합니까? C++에는 함수의 부분적인 특수화가 없으므로 swap을 특수화 할 수 없습니다. 유일한 선택은 오버로딩이지만 표준에서는 std 네임 스페이스에 오버로드를 추가 할 수 없다고 말합니다.

당신은이 시점에서 두 가지 옵션이 있습니다

  1. 자신의 네임 스페이스에 swap(Foo<T>&, Foo<T>&) 기능을 만들기를하고 ADL을 통해 발견됩니다 바랍니다. 표준 라이브러리가 std::swap(a, b);처럼 스왑을 호출하면 ADL이 작동하지 않기 때문에 "희망"이라고 말합니다.

  2. 표준의 오버로드를 추가하지 말고 무시하는 부분은 무시하십시오. 솔직히 기술적으로 허용되지는 않지만 모든 현실적인 시나리오에서 작동 할 것입니다.

기억해야 할 점은 표준 라이브러리가 swap을 전혀 사용하지 않는다는 것입니다. 대부분의 알고리즘은 std::iter_swap을 사용하고 일부 구현에서는 살펴 보았지만 항상 std::swap으로 전달하지는 않습니다.

+0

이 좋은 예 선생님 – tenfour

+6

...이 점을 지적했다 "나는 희망이 있기 때문에 말을"

template<class T> T zero(); template<> int zero() { return 0; } template<> long zero() { return 0L; } 

기능 오버로드를 사용하여 비슷한 작업을 수행하려면, 당신은 함수 서명에 매개 변수를 추가해야 몇 년 전에 WG21에서 모든 표준 라이브러리 구현자는 알지 못합니다. – MSalters

+0

멋진 답변, 정말 고마워요. –

5

std 네임 스페이스의 함수를 오버로드 할 수 없지만 템플릿을 특수화 할 수 있으므로 (상기 한 것처럼) 하나의 옵션입니다.

다른 옵션은 swap 함수를 작동중인 것과 동일한 네임 스페이스에 넣고 using std::swap;을 정규화되지 않은 스왑을 호출하기 전에 넣는 것입니다.

+0

''std :: swap;을 사용하여''네임 스페이스 std;를 사용하는 것을 선호합니다. –

+0

일부 템플릿을 전문화 할 수 있습니다. _ "프로그램이 사용자 정의 유형에 따라 선언이 달라지고 전문화가 원본 템플리트의 표준 라이브러리 요구 사항을 충족하고 그렇지 않은 경우에만 표준 라이브러리 템플리트에 대한 템플리트 전문화를 네임 스페이스 std에 추가 할 수 있습니다 명백히 금지되어 있습니다. "_ [n3337; 17.6.4.2.1/1] 그래서'std'에없는 타입을 위해'std :: swap'을 전문화 할 수 있습니다. – boycy

+0

왜 std 함수를 오버로드 할 수 없습니까? 나쁜 습관이지만 std 네임 스페이스는 특별하지 않습니다. 나는 그것을 좋아하지 않지만, 많은 제품들이 std 네임 스페이스에서 그들의 타입을위한 std swap을 추가한다. – Nick

10

피터 알렉산더 (Peter Alexander)의 답변에 추가 할 내용이 거의 없습니다. 함수 전문화가 오버로드보다 우월 할 수 있다는 점을 언급하기로하겠습니다. 매개 변수없이 함수 중에서 선택해야합니다.

예.

int zero(int) { return 0; } 
long zero(long) { return 0L; } 
+1

흥미로운 사용법 :) –