// 실수에서 정수로 변환하는 경우
double d = 3.14;
int i = d; // i는 3이됨
// uniform initialization은 암묵적 좁히기 변환을 방지함
int x = 3.14; // 허용 x는 3
int y(3.14); // 허용 y는 3
int z{3.14}; // 컴파일 오류
class Widget
{
public:
Widget(int i, bool b); // (1)
Widget(int i, double d); // (2)
// ...
};
Widget w1(10, true); // (1) 호출
Widget w2{10, true}; // (1) 호출
Widget w3(10, 5.0); // (2) 호출
Widget w4{10, 5.0}; // (2) 호출
여기 까지는 예상대로 동작함
그러나 생성자 중 하나 이상이 std::initializer_list
형식의 매개변수를 선언하면 초기화 구문은 이 버전을 강하게 선호함
class Widget
{
public:
Widget(int i, bool b); // (1)
Widget(int i, double d); // (2)
Widget(std::initializer_list<long double> il); // (3)
};
Widget w1(10, true); // (1) 호출
Widget w2{10, true}; // (3) 호출 10과 true가 long double로 변환됨
Widget w3(10, 5.0); // (2) 호출
Widget w4{10, 5.0}; // (3) 호출 10과 5.0이 long double로 변환됨
생성자 중 정확히 형식이 일치하는 경우가 있음에도 불구하고 std::initializer_list<bool>
을 호출하려고 함
bool
로 변환하기 위해서는 좁히기 변환이 필요하지만 uniform initialization
은 이를 방지하므로 컴파일 에러가 발생함 (정확히 형식이 일치하는 생성자가 있음에도 불구하고.. 🤔)
class Widget
{
public:
Widget(int i, bool b); // (1)
Widget(int i, double d); // (2)
Widget(std::initializer_list<bool> il); // (3)
};
Widget w4{10, 5.0}; // 컴파일 에러
우선 순위를 가지는 정도가 아니라 다른 생성자가 고려 대상에서 제외될 정도로 가려버림
이 문제에 직접 영향을 받는 클래스 중 하나가 vector
임
vector
는 비std::initializer_list
생성자와 std::initializer_list
생성자 둘 다 있기 때문
vector<int> v1(1, 2); // 비 std::initializer_list 생성자 사용
// 모든 요소의 값이 2인 요소 1개짜리 vector가 생성됨
vector<int> v2{1, 2}; // std::initializer_list 생성자 사용
// 값이 1, 2인 두 요소를 담은 vector가 생성됨
=> 클래스를 작성할 때 생성자 중에 std::initializer_list
를 받는 함수가 하나 이상 존재한다면 중괄호 초기화 사용을 주의해야 함을 기억하자
std::initializer_list
를 인자로 받는 생성자가 있다면 전달됨initializer_list<int> il = { 1, 2, 3 };
il.begin()[0] = 10; // 컴파일 오류
초기화는 std::initializer_list 생성자로 호출되지만 값을 복사하여 vector에 데이터를 저장하기 때문에 생성된 이후 initializer_list와 상관없이 값 변경이 가능함
=> std::initializer_list
는 불변이지만 이를 사용해 초기화된 컨테이너는 컨테이너의 특성에 따라 값을 변경할 수 있음