pack_indexing — 팩 인덱싱

pack_indexing — 팩 인덱싱 (Pack indexing)

**팩 인덱싱(pack indexing)**은 지정된 인덱스에 있는 파라미터 팩(pack)의 요소에 접근하는 기능이에요. C++26에서 도입됐어요.

가변 인자 템플릿에서 팩의 특정 위치 요소를 가져오고 싶을 때 써요. 예전에는 헬퍼 함수나 재귀로 해야 했는데, P...[I] 같은 표기로 직접 접근할 수 있게 됐어요.

출처: cppreference

본문

팩 인덱싱은 지정된 인덱스에 있는 팩의 요소에 접근해요.

문법 (Syntax)

id-expression ...[ expression ]
typedef-name ...[ expression ]
  1. 팩 인덱싱 표현식 (pack indexing expression)
  2. 팩 인덱싱 지정자 (pack indexing specifier)
  • typedef-name — 팩을 이름 짓는 식별자 또는 simple-template-id
  • id-expression — 팩을 이름 짓는 id-expression
  • expressionstd::size_t 타입의 변환 상수 표현식 I. 팩 인덱싱에서 어떤 팩 P에 대해 I[0, sizeof...(P)) 범위 안에 있어야 해요.

설명 (Explanation)

팩 인덱싱은 펼쳐지지 않은 팩 뒤에 생략부호와 첨자 안의 인덱스가 오는 "팩 확장"이에요. 두 가지 종류가 있어요: 팩 인덱싱 표현식과 팩 인덱싱 지정자.

PP0, P1, ..., Pn-1을 포함하는 비어 있지 않은 팩이고 I가 유효한 인덱스일 때, 확장 P...[I]의 인스턴스화는 P의 팩 요소 PI를 산출해요.

상수 표현식이 아닌 인덱스 I로 팩을 인덱싱하는 것은 허용되지 않아요.

팩 인덱싱 표현식

id-expression ...[ expression ]

팩 인덱싱 표현식은 팩 요소 PI의 표현식인 id-expression을 나타내요. id-expression은 다음의 선언으로 도입되어야 해요.

  • 비타입 템플릿 매개변수 팩
  • 함수 매개변수 팩
  • 람다 init-capture 팩
  • 구조적 바인딩 팩

잘못된 예시:

template <std::size_t I, auto... Vals>
constexpr auto identity_at = (Vals)...[I]; // 오류: 'Vals...[I]' 를 쓰세요

template <std::size_t I, std::size_t... Vals>
constexpr std::size_t triple_at = (Vals * 3)...[I]; // 오류
// 'Vals...[I] * 3' 을 쓰세요

template <std::size_t I, typename... Args>
constexpr decltype(auto) get(Args&&... args) noexcept
{
    return std::forward<Args>(args)...[I]; // 오류
    // 'std::forward<Args...[I]>(args...[I])' 을 쓰세요
}

팩 인덱싱 표현식에 decltype을 적용하는 것은 id-expression에 decltype을 적용하는 것과 같아요.

팩 인덱싱 지정자

typedef-name ...[ expression ]

팩 인덱싱 지정자는 팩 요소 PI의 타입인 computed-type-specifier를 나타내요. typedef-name은 타입 템플릿 매개변수 팩의 선언으로 도입되어야 해요.

팩 인덱싱 지정자는 단순 타입 지정자, 기반 클래스 지정자, 중첩 이름 지정자, 또는 명시적 소멸자 호출의 타입으로 쓰일 수 있어요.

팩 인덱싱 지정자는 함수나 생성자 매개변수 목록에서 템플릿 인자 추론의 비추론 문맥(non-deduced contexts)을 설정하는 데 사용될 수 있어요.

노트 (Notes)

Ts...[N]은 크기 N의 이름 없는 배열인 함수 매개변수 팩을 선언하는 유효한 문법이었는데, 매개변수 타입은 포인터로 조정됐어요. C++26부터 Ts...[1]은 팩 인덱싱 지정자로 해석되어 동작이 달라져요. 첫 번째 동작을 유지하려면 함수 매개변수 팩에 이름을 붙이거나 포인터 팩으로 수동 조정해야 해요.

팩 인덱싱은 C++26 기능으로, 기능 테스트 매크로 __cpp_pack_indexing202311L 값을 가져요.

예제 (Example)

#include <tuple>

template <std::size_t... Indices, typename Decomposable>
constexpr auto splice(Decomposable d)
{
    auto [...elems] = d;
    return std::make_tuple(elems...[Indices]...);
}

struct Point
{
    int x;
    int y;
    int z;
};

int main()
{
    constexpr Point p { .x = 1, .y = 4, .z = 3 };
    static_assert(splice<2, 1, 0>(p) == std::make_tuple(3, 4, 1));
    static_assert(splice<1, 1, 0, 0>(p) == std::make_tuple(4, 4, 1, 1));
}

elems...[Indices]...에서 Indices 팩의 각 인덱스로 elems 팩 요소를 꺼내 튜플을 만드는 예제예요. 인덱스 순서를 바꿔서 요소 순서를 재배치할 수 있답니다.

더 알아보기 (Learn more)

cppreference