language_list_initialization
language_list_initialization (리스트 초기화, 중괄호 초기화)
중괄호로 감싼 초기화자 목록(braced-init-list)으로 객체를 초기화해요. C++11부터 도입된, 가장 다재다능하고 좁히기 변환을 막아주는 초기화 방식이에요.
출처: cppreference
본문
문법
직접 리스트 초기화 (Direct-list-initialization)
T object { arg1, arg2, ... }; // (1)
T object {.des1 = arg1 , .des2 { arg2 } ... }; // (1) since C++20
T { arg1, arg2, ... } // (2)
T {.des1 = arg1 , .des2 { arg2 } ... } // (2) since C++20
new T { arg1, arg2, ... } // (3)
new T {.des1 = arg1 , .des2 { arg2 } ... } // (3) since C++20
Class { T member { arg1, arg2, ... }; }; // (4)
Class { T member {.des1 = arg1 , .des2 { arg2 } ... }; }; // (4) since C++20
Class::Class() : member { arg1, arg2, ... } {...} // (5)
Class::Class() : member {.des1 = arg1 , .des2 { arg2 } ...} {...} // (5) since C++20
복사 리스트 초기화 (Copy-list-initialization)
T object = { arg1, arg2, ... }; // (6)
T object = {.des1 = arg1 , .des2 { arg2 } ... }; // (6) since C++20
function ({ arg1, arg2, ... }) // (7)
function ({.des1 = arg1 , .des2 { arg2 } ... }) // (7) since C++20
return { arg1, arg2, ... }; // (8)
return {.des1 = arg1 , .des2 { arg2 } ... }; // (8) since C++20
object [{ arg1, arg2, ... }] // (9)
object [{.des1 = arg1 , .des2 { arg2 } ... }] // (9) since C++20
object = { arg1, arg2, ... } // (10)
object = {.des1 = arg1 , .des2 { arg2 } ... } // (10) since C++20
U ({ arg1, arg2, ... }) // (11)
U ({.des1 = arg1 , .des2 { arg2 } ... }) // (11) since C++20
Class { T member = { arg1, arg2, ... }; }; // (12)
Class { T member = {.des1 = arg1 , .des2 { arg2 } ... }; }; // (12) since C++20
설명
리스트 초기화는 다음 상황에서 수행돼요.
- 직접 리스트 초기화: 중괄호 목록으로 직접 초기화. explicit·비-explicit 생성자 모두 사용 가능.
- 복사 리스트 초기화:
=뒤 중괄호 목록으로 초기화. explicit 생성자는 사용할 수 없어요.
리스트 초기화의 핵심은 좁히기 변환(narrowing conversion) 금지예요. 예를 들어 double을 int 초기화에 넣으면 컴파일 오류가 나요. 또, 생성자 오버로드 해석에서 std::initializer_list 생성자가 다른 생성자보다 우선해요.
int x { 3.14 }; // 오류: 좁히기 변환
std::vector<int> v{1, 2, 3}; // initializer_list 생성자 사용
C++20부터 지정 초기화(designated initializer)로 멤버 이름을 지정해 초기화할 수도 있어요.