내 수업에 스왑 기능을 제공하는 방법은 무엇입니까?


87

swapSTL 알고리즘 을 활성화하는 적절한 방법은 무엇입니까 ?

1) 회원 swap. 합니까는 std::swap멤버를 사용하는 SFINAE의 트릭을 사용합니다 swap.

2) swap동일한 네임 스페이스에서 독립형 .

3) std::swap.

4) 위의 모든 것.

감사합니다.

편집 : 내 질문을 명확하게 말하지 않은 것 같습니다. 기본적으로 템플릿 클래스가 있으며 해당 클래스에 대해 작성한 (효율적인) 스왑 방법을 사용하려면 STL 알고리즘이 필요합니다.

답변:


94
  1. 의 적절한 사용 입니다 swap. "라이브러리"코드를 작성하고에서 ADL (인수 종속 조회)을 활성화하려는 경우 이렇게 작성합니다 swap. 또한 이것은 SFINAE와 관련이 없습니다.
// some algorithm in your code
template<class T>
void foo(T& lhs, T& rhs) {
    using std::swap; // enable 'std::swap' to be found
                    // if no other 'swap' is found through ADL
    // some code ...
    swap(lhs, rhs); // unqualified call, uses ADL and finds a fitting 'swap'
                    // or falls back on 'std::swap'
    // more code ...
}
  1. swap클래스에 대한 함수 를 제공하는 적절한 방법 입니다.
namespace Foo {

class Bar{}; // dummy

void swap(Bar& lhs, Bar& rhs) {
    // ...
}

}

경우 swap1과 같이 현재)를 사용, 함수가 발견됩니다. 또한 꼭 필요한 경우 해당 함수를 친구로 만들거나 swapfree 함수에 의해 호출되는 멤버 를 제공 할 수 있습니다.

// version 1
class Bar{
public:
    friend void swap(Bar& lhs, Bar& rhs) {
    // ....
    }
};

// version 2
class Bar{
public:
    void swap(Bar& other) {
    // ...
    }
};

void swap(Bar& lhs, Bar& rhs) {
    lhs.swap(rhs);
}

...
  1. 당신은 명시적인 전문화를 의미합니다. Partial은 여전히 ​​다른 것이고 함수에 대해서도 가능하지 않으며 구조체 / 클래스 만 가능합니다. 당신은 전문 수 없기 때문에 이와 같이, std::swap템플릿 클래스, 당신은 네임 스페이스에 무료 기능을 제공 할 수 있습니다. 내가 그렇게 말할 수 있다면 나쁜 것은 아닙니다. 이제 명시 적 전문화도 가능하지만 일반적으로 함수 템플릿을 전문화하고 싶지 않습니다 .
namespace std
{  // only allowed to extend namespace std with specializations

template<> // specialization
void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
    // ...
}

}
  1. 아니요, 1)은 2) 및 3)와 구별됩니다. 또한 2)와 3)을 모두 가지고 있으면 더 잘 맞기 때문에 항상 2)가 선택됩니다.

8
내가 뭔가를 잘못 읽지 않는 한 귀하의 (1)과 질문의 (1)은 실제로 일치하지 않습니다. 여전히, +1
Dennis Zickefoose 2011 년

1
@Xeo. 입력 해 주셔서 감사합니다. 내 질문을 수정했습니다. STL은 사례 1에서 설명한대로 스왑을 사용합니까?
pic11

1
@pic : 예, STL은 1)에서 보여 드린 ADL 스왑을 사용하지만 멤버 함수뿐만 아니라 무료 함수로있는 경우에만 사용합니다. 2) 및 3)를 참조하십시오. 두 버전 모두 알고리즘에 의해 선택됩니다. 2) 3)이 오래되어 나쁜 습관으로 간주되기 때문에 나는 조언하고 싶습니다.
Xeo

2
첫 번째 코드의 주석은 오해의 소지가 있습니다. using std::swap;ADL을 활성화하지 않고 std::swapADL이 적절한 오버로드를 찾지 못하는 경우 컴파일러가 찾을 수 있도록합니다 .
David Rodríguez-dribeas 2011-06-19

6
이 답변은 기술적으로 정확하지만 명확성을 위해 편집 이 절실히 필요합니다. OP의 (1)은 정답이 아닙니다.이 답변의 지나치게 빠른 읽기는 실수로 표시되는 것처럼 보입니다.
하워드 Hinnant

1

클래스가 템플릿 클래스 일 수있는 EDIT에 응답하려면 전문화가 전혀 필요하지 않습니다. 다음과 같은 클래스를 고려하십시오.

template <class T>
struct vec3
{
    T x,y,z;
};

다음과 같은 클래스를 정의 할 수 있습니다.

vec3<float> a;
vec3<double> b;
vec3<int> c;

3 개의 스왑을 모두 구현하는 하나의 함수를 만들 수 있도록하려면 (이 예제 클래스가 보증하는 것은 아님) Xeo가 (2)에서 말한 것처럼 전문화하지 않고 일반 템플릿 함수를 만듭니다.

template <class T>
void swap(vec3<T> &a, vec3<T> &b)
{
    using std::swap;
    swap(a.x,b.x);
    swap(a.y,b.y);
    swap(a.z,b.z);
}

스왑 템플릿 함수는 스왑하려는 클래스와 동일한 네임 스페이스에 있어야합니다. 다음 메서드는 ADL을 사용하여 해당 네임 스페이스를 참조하지 않는 경우에도 해당 스왑을 찾아 사용합니다.

using std::swap;
swap(a,b);

0

네임 스페이스에 선언을 추가하는 것은 일반적으로 정의되지 않은 동작 이기 때문에 (2) ( 사용자 정의 클래스가 선언 된 동일한 네임 스페이스에있는 독립형swap ) 은 사용자 정의 클래스 를 제공 할 수있는 유일한 방법 인 것 같습니다 . 네임 스페이스 std (cppreference.com) 확장 :swapstd

네임 스페이스 std또는에 중첩 된 네임 스페이스에 선언 또는 정의를 추가하는 것은 정의되지 않은 동작이며 std아래에 몇 가지 예외가 있습니다.

그리고 swap이러한 예외 중 하나로 표시되지 않습니다. 따라서 네임 스페이스에 자체 swap오버로드를 추가 std하는 것은 정의되지 않은 동작입니다.

또한 표준 라이브러리는 이러한 사용자 정의 가 제공되는 경우 사용자 클래스에 대해 사용자 swap정의를 호출하기 위해 함수에 대한 정규화되지 않은 호출을 사용한다고합니다 .swapswap

스왑 가능 (cppreference.com) :

많은 표준 라이브러리 함수 (예 : 많은 알고리즘)는 인수가 Swappable 을 만족할 것으로 예상합니다. 즉, 표준 라이브러리가 스왑을 수행 할 때마다 using std::swap; swap(t, u);.

스왑 (www.cplusplus.com) :

(내 표준 라이브러리의 많은 구성 요소 std호출) swap에서 비정규 의 사용자 정의 오버로드 : 방식이 아닌 기본 유형의 사용자 정의 오버로드 대신 일반 버전의 호출 할 수 있도록 swap그들이 선택받을 제공되는 유형과 같은 네임 스페이스 선언을 를 통해 인수 의존 검색 이 일반 버전 이상.

그러나 std::swap사용자 정의 클래스에 대한 함수를 직접 사용하면 사용자 정의 std::swap대신 일반 버전이 호출 됩니다 swap.

my::object a, b;
std::swap(a, b); // calls std::swap, not my::swap

따라서 swap표준 라이브러리에서 수행되는 것과 동일한 방식으로 사용자 코드에서 함수 를 호출하는 것이 좋습니다 .

my::object a, b;
using std::swap;
swap(a, b); // calls my::swap if it is defined, or std::swap if it is not.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.