ranges_swap
ranges_swap (ranges::swap 사용자 지정 지점 객체)
이 페이지는 C++20에서 도입된 std::ranges::swap 사용자 지정 지점 객체에 대해 설명해요. ranges::swap(t, u)는 두 값 t와 u가 참조하는 값을 교환하는 표현식이에요. 이 함수는 다양한 유형의 인자에 대해 적절한 교환 방식을 자동으로 선택해요.
출처: cppreference
본문
정의
| 항목 | 내용 |
|---|---|
| 헤더 | <concepts> |
| 네임스페이스 | namespace ranges { inline namespace /* unspecified */ { inline constexpr /* unspecified */ swap = /* unspecified */ ; } } |
| 도입 | (since C++20) (customization point object) |
| 호출 시그니처 | template < class T , class U > constexpr void ranges :: swap ( T && t , U && u ) noexcept ( /* see below */ ); (since C++20) |
동작 방식
ranges::swap(t, u)는 t와 u가 참조하는 값을 교환해요. 이 표현식은 다음과 같은 규칙에 따라 결정돼요.
-
t나u가 클래스 또는 열거형 타입이고 해당 표현식이 유효하다면,(void) swap(t, u)와 동일해요. 이때 오버로드 해석은std::ranges네임스페이스 안에서 추가 후보template<class T> void swap(T&, T&) = delete;와 함께 수행돼요. 오버로드 해석으로 선택된 함수가t와u가 참조하는 값을 교환하지 않는다면, 프로그램은 진단 없이 ill-formed예요. -
그렇지 않고,
t와u가 같은 크기의 lvalue 배열이고(요소 타입은 달라도 돼요)ranges::swap(*t, *u)가 유효한 표현식이라면,(void) ranges::swap_ranges(t, u)와 동일해요. 단,noexcept((void) ranges::swap_ranges(t, u))는noexcept(ranges::swap(*t, *u))와 같아요. -
그렇지 않고,
t와u가 모두std::move_constructible<V>와std::assignable_from<V&, V>를 만족하는 같은 타입V의 lvalue라면,t와u가 참조하는 값을 교환하는 표현식과 동일해요. 그 표현식에noexcept연산자를 적용한 결과는std::is_nothrow_move_constructible_v<V> && std::is_nothrow_move_assignable_v<V>와 같아요.V가 LiteralType이고,t = std::move(u)와u = std::move(t)가 모두 상수 부분 표현식이며, 다음 선언들의 초기화 전체 표현식이 상수 부분 표현식이라면 그 표현식은 상수 표현식이에요:V v1(std::move(t)); V v2(std::move(u)); -
그 외의 경우
ranges::swap(t, u)는 ill-formed예요. 이는ranges::swap(t, u)가 템플릿 인스턴스화의 immediate context에 나타날 때 치환 실패(substitution failure)로 이어질 수 있어요.
사용자 지정 지점 객체
ranges::swap이라는 이름은 사용자 지정 지점 객체(customization point object)를 나타내요. 이는 리터럴 세미레귤러 클래스 타입의 const 함수 객체예요. 자세한 내용은 CustomizationPointObject를 참고하세요.
예제
#include <array>
#include <concepts>
#include <iostream>
#include <ranges>
#include <string_view>
#include <vector>
void print(std::string_view name,
std::ranges::common_range auto const& p,
std::ranges::common_range auto const& q)
{
std::cout << name << "1{ ";
for (auto const& i : p)
std::cout << i << ' ';
std::cout << "}, " << name << "2{ ";
for (auto const& i : q)
std::cout << i << ' ';
std::cout << "}\n";
}
void print(std::string_view name, int p, int q)
{
std::cout << name << "1 = " << p << ", " << name << "2 = " << q << '\n';
}
struct IntLike
{
int v;
};
void swap(IntLike& lhs, int& rhs)
{
std::swap(lhs.v, rhs);
}
void swap(int& lhs, IntLike& rhs)
{
std::swap(lhs, rhs.v);
}
std::ostream& operator<<(std::ostream& out, IntLike i)
{
return out << i.v;
}
int main()
{
std::vector a1{10, 11, 12}, a2{13, 14};
std::ranges::swap(a1, a2);
print("a", a1, a2);
std::array b1{15, 16, 17}, b2{18, 19, 20};
std::ranges::swap(b1, b2);
print("b", b1, b2);
// std::array c1{1, 2, 3}; std::array c2{4, 5};
// std::ranges::swap(c1, c2); // error: no swap found by ADL
int d1[]{21, 22, 23}, d2[]{24, 25, 26};
std::ranges::swap(d1, d2);
print("d", d1, d2);
// int e1[]{1, 2, 3}, e2[]{4, 5};
// std::ranges::swap(e1, e2); // error: extents mismatch
// char f1[]{1, 2, 3};
// int f2[]{4, 5, 6};
// std::ranges::swap(f1, f2); // error: no swap(*f1, *f2) found by ADL
IntLike g1[]{1, 2, 3};
int g2[]{4, 5, 6};
std::ranges::swap(g1, g2); // heterogeneous swap supported
print("g", g1, g2);
int h1{27}, h2{28};
std::ranges::swap(h1, h2);
print("h", h1, h2);
}
출력:
a1{ 13 14 }, a2{ 10 11 12 }
b1{ 18 19 20 }, b2{ 15 16 17 }
d1{ 24 25 26 }, d2{ 21 22 23 }
g1{ 4 5 6 }, g2{ 1 2 3 }
h1 = 28, h2 = 27
같이 보기
| 항목 | 설명 |
|---|---|
swappable, swappable_with (C++20) |
한 타입이 교환 가능하거나 두 타입이 서로 교환 가능함을 지정하는 개념 (concept) |
swap |
두 객체의 값을 교환하는 함수 템플릿 |