글을 쓰는 방법은 여러 가지가 있는데 swap
, 다른 방법 보다 낫습니다. 그러나 시간이 지남에 따라 단일 정의가 가장 효과적이라는 것이 발견되었습니다. swap
함수 작성에 대해 어떻게 생각할 수 있는지 생각해 봅시다 .
먼저 컨테이너와 같은 컨테이너에는 다음과 같은 std::vector<>
단일 인수 멤버 함수 swap
가 있습니다.
struct vector
{
void swap(vector&) { /* swap members */ }
};
당연히 우리 수업도 그래야합니까? 글쎄,별로. 표준 라이브러리에는 모든 종류의 불필요한 것들이 있으며 멤버 swap
는 그중 하나입니다. 왜? 계속하자.
우리가해야 할 일은 표준적인 것이 무엇인지, 그리고 클래스 가 함께 일하기 위해해야 할 일을 식별하는 것입니다. 그리고 표준 스와핑 방법은입니다 std::swap
. 이것이 멤버 함수가 유용하지 않은 이유입니다. 일반적으로 함수를 바꾸는 방법이 아니고의 동작과 관련이 없습니다 std::swap
.
그렇다면 std::swap
우리가 일을하려면 std::vector<>
전문화를 제공해야하고, 제공해야했을 std::swap
까요?
namespace std
{
template <> // important! specialization in std is OK, overloading is UB
void swap(myclass&, myclass&)
{
// swap
}
}
이 경우에는 분명히 효과가 있지만 눈에 띄는 문제가 있습니다. 함수 전문화는 부분적 일 수 없습니다. 즉, 우리는 이것으로 템플릿 클래스를 특수화 할 수 없으며 특정 인스턴스화 만 가능합니다.
namespace std
{
template <typename T>
void swap<T>(myclass<T>&, myclass<T>&) // error! no partial specialization
{
// swap
}
}
이 방법은 일부 시간에는 작동하지만 항상 작동하지는 않습니다. 더 좋은 방법이 있어야합니다.
있습니다! friend
함수 를 사용하고 ADL 을 통해 찾을 수 있습니다 .
namespace xyz
{
struct myclass
{
friend void swap(myclass&, myclass&);
};
}
무언가를 교환하고 싶을 때 † 를 연결 std::swap
한 다음 자격이없는 전화를 겁니다.
using std::swap; // allow use of std::swap...
swap(x, y); // ...but select overloads, first
// that is, if swap(x, y) finds a better match, via ADL, it
// will use that instead; otherwise it falls back to std::swap
friend
기능 이란 무엇입니까 ? 이 지역에 혼란이 있습니다.
C ++가 표준화되기 전에 friend
함수는 "friend name injection" 이라는 기능을 수행했는데 마치 함수가 마치 네임 스페이스에서 작성된 것처럼 코드가 동작 했습니다 . 예를 들어, 이들은 동일한 사전 표준이었습니다.
struct foo
{
friend void bar()
{
// baz
}
};
// turned into, pre-standard:
struct foo
{
friend void bar();
};
void bar()
{
// baz
}
그러나 ADL 이 발명 되었을 때 이것은 제거되었습니다. 이 friend
기능은 ADL 을 통해서만 찾을 수 있습니다. 자유 함수로 원한다면 선언해야합니다 ( 예 : this 참조 ). 그러나 소호! 문제가 발생했습니다.
당신이 방금 사용한다면 , 당신은 명시 적으로 "찾고 , 다른 곳은 없다 "고 말했기 때문에 std::swap(x, y)
과부하를 찾지 못할 것입니다 std
! 그렇기 때문에 일부 사람들은 ADL을 통해 찾을 수있는 기능 과 명시적인 std::
자격 을 처리하기 위해 두 가지 기능을 작성하도록 제안했습니다 .
그러나 우리가 본 것처럼, 이것은 모든 경우에 작동하지 않으며 결국 추악한 혼란으로 끝납니다. 대신, 관용적 스와핑은 다른 길로 나아갔습니다. 클래스를 제공하는 작업 대신 , 위와 같이 std::swap
Qualified를 사용하지 않도록하는 것은 스왑 퍼의 일 swap
입니다. 사람들이 알고있는 한 이것은 잘 작동하는 경향이 있습니다. 그러나 거기에는 문제가있다 : 자격이없는 전화를 사용하는 것은 직관적이지 않다!
이를 쉽게하기 위해 Boost와 같은 일부 라이브러리 는 관련 네임 스페이스 와 함께 boost::swap
정규화되지 않은 호출을 수행하는 함수를 제공했습니다 . 이것은 일을 간결하게 만드는 데 도움이되지만 여전히 혼란 스럽습니다.swap
std::swap
C ++ 11에는의 동작에 대한 변경 사항이 없으므로 std::swap
나와 다른 사람들이 실수라고 생각했습니다. 이것에 조금 익숙하다면 여기를 읽으십시오 .
한마디로 : 멤버 함수는 잡음이 많고 전문화는 추악하고 불완전하지만 friend
함수는 완전하고 작동합니다. 그리고 당신이 교환 할 때, boost::swap
또는 관련 이없는 자격 swap
을 사용하십시오 std::swap
.
† 비공식적으로 이름은 함수 호출 중에 고려 될 경우 연결 됩니다. 자세한 내용은 §3.4.2를 참조하십시오. 이 경우 std::swap
일반적으로 고려되지 않습니다. 그러나 이를 찾을 수 있도록 연결할 수 있습니다 (unqualified에서 고려한 과부하 세트에 추가 swap
).