template_for — template for 확장 문

template_for — template for 확장 문

template for 확장 문은 컴파일 타임에 결정 가능한 언어 구조를 그 요소들로 확장해요. 같은 로직을 여러(아마 이질적인) 표현식에 적용하는 여러 문장보다 더 읽기 쉬운 동등 표현으로 사용돼요.

런타임 반복 대신 컴파일 타임에 펼쳐지므로, 타입이 서로 다른 여러 값을 순회하면서 각각에 같은 연산을 적용할 수 있어요. C++26에서 도입된 기능이에요.

출처: cppreference

본문

template for 확장 문은 컴파일 타임에 결정 가능한 언어 구조를 그 요소들로 확장해요. 같은 로직을 여러(아마 이질적인) 표현식에 적용하는 여러 문장보다 더 읽기 쉬운 동등 표현으로 사용돼요.

문법 (Syntax)

attr template for ( init-statement item-declaration : expansion-initializer ) compound-statement
  • attr — 임의 개수의 속성
  • init-statement — 다음 중 하나
    • 표현식 문장 (빈 문장 ;일 수 있음)
    • 단순 선언 (보통 초기화자가 있는 변수 선언). 임의의 여러 변수나 구조적 바인딩 선언일 수 있어요.
    • 타입 별칭(alias) 선언
  • item-declaration — 다음 중 하나
    • 제한이 있는 단순 선언 (선언자가 하나, 초기화자가 없어야 하고, 지정자 시퀀스에 타입 지정자와 constexpr만 허용됨)
    • 구조적 바인딩 선언
  • expansion-initializer — 다음 중 하나
    • 표현식
    • 쉼표로 구분된 표현식 목록 (후행 쉼표 가능, 중괄호로 감쌈)
  • compound-statement — 어떤 복합 문장

확장 문을 위해 break 문을 종료 문장으로, continue 문을 지름길로 쓸 수 있어요.

확장 문의 세 종류

expansion-initializer의 문법과 속성에 따라 template for 문은 세 가지 범주 중 하나로 나뉘어요.

열거 확장 문 (Enumerating expansion statement)

expansion-initializer가 중괄호로 감싼 표현식 목록이면 열거 확장 문이에요. 표현식 목록의 각 요소를 순서대로 펼쳐서, 각 요소에 대해 item-declaration과 복합 문장을 실행해요.

반복 확장 문 (Iterating expansion statement)

expansion-initializer가 확장-반복 가능(expansion-iterable) 표현식이면 반복 확장 문이에요. 배열 타입 참조, begin/end 멤버를 가진 클래스, 또는 ADL로 찾은 begin/end 함수를 지원하는 타입에 대해 범위 기반으로 반복해요.

분해 확장 문 (Destructuring expansion statement)

expansion-initializer가 확장-반복 불가능 표현식이면 분해 확장 문이에요. 구조적 바인딩 크기만큼 펼쳐서, 각 바인딩에 대해 복합 문장을 실행해요.

임시 확장 초기화자 (Temporary expansion initializer)

열거 확장 문에서 표현식 목록의 어떤 요소 expr에서 임시 객체가 생성되고 그 객체가 expr의 전체 표현식 끝에서 파괴될 것이라면, 그 객체는 expr로부터 초기화된 item-declaration의 수명 동안 지속돼요.

이 기능은 C++26의 확장 문으로, 기능 테스트 매크로 __cpp_expansion_statements202506L 값을 가져요.

예제 (Example)

#include <array>
#include <vector>

constexpr int f1(const auto&... containers)
{
    int result = 0;
    template for (const auto& c : {containers...}) // 열거 확장 문
        result += c[0];

    return result;
}

constexpr int f2()
{
    constexpr std::array<int, 3> arr{1, 2, 3};
    int result = 0;
    template for (constexpr int s : auto(arr)) // 반복 확장 문
        result += s;

    return result;
}

struct S
{
    int i;
    short s;
};

constexpr long f3(S s)
{
    long result = 0;
    template for (auto x : s) // 분해 확장 문
        result += sizeof(x);

    return result;
}

int main()
{
    constexpr int c1[] = {1, 2, 3};
    constexpr int c2[] = {4, 3, 2, 1};
    static_assert(f1(c1, c2) == 5); // c1[0] + c2[0]

    static_assert(f2() == 6); // 1 + 2 + 3

    static_assert(f3(S{}) == sizeof(int) + sizeof(short));
}

f1은 서로 다른 크기의 두 배열 c1, c2template for로 순회하며 각각의 첫 요소(c1[0] + c2[0])를 더하고, f2std::array를, f3은 구조체 S의 각 멤버를 분해 순회하며 크기를 더해요. 모든 계산이 컴파일 타임(static_assert)에 확정되는 점이 핵심이에요.

더 알아보기 (Learn more)

cppreference