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_statements가 202506L 값을 가져요.
예제 (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, c2를 template for로 순회하며 각각의 첫 요소(c1[0] + c2[0])를 더하고, f2는 std::array를, f3은 구조체 S의 각 멤버를 분해 순회하며 크기를 더해요. 모든 계산이 컴파일 타임(static_assert)에 확정되는 점이 핵심이에요.