Uniform Initialization
Uniform Initialization
객체를 생성자와 함께 호출하려면 ( ) 를 사용했다.
// vector(size_type count, const T& value) 호출해서 생성
vector<int> vec(3, 10);
- Most Vexing Parse
아래의 경우에는 무슨 일이 일어날까?
기본생성자? vector를 리턴하고 인자를 받지않는 vec 함수?
c++에서는 이것을 함수의 선언으로 생각한다.
vector<int> vec();
class A {
public:
A() { std::cout << "A 의 생성자 호출!" << std::endl; }
};
class B {
public:
B(A a) { std::cout << "B 의 생성자 호출!" << std::endl; }
};
// c++ 컴파일러?는 애매한 표현을 허용해서 최적의 코드로 변환하는데,
// 아래 코드는 A()가 익명타입 생성으로 B b(A anonymous)로 해석하는느낌
B b(A());
함수 선언과 헷갈리는 문제를 해결하기 위해 { } 를 사용해서 모든 타입에 대해 일관된 초기화 방식을 제공한다.
생성자를 사용해서 순서대로 인자를 전달해주는 것이기 때문에 커스텀 클래스도 생성자만 구현해두면 된다.
단, 손실이 발생하는(Narrowing) 타입변환(=축소변환)을 지원하지 않아서 안전한 프로그래밍이 가능하다. (생성자는 int인데, float 데이터를 전달한 경우)
std::list<int> my_list{1, 2, 3, 4, 5};
std::set<int> my_set{3, 1, 5, 2, 4};
class CustomClass {
public:
std::string name;
int value;
CustomClass(const std::string& _name, int _value)
: name(_name), value(_value) {}
};
CustomClass obj1{"object1", 1};
std::map<std::string, CustomClass> my_map{
{"one", {"kdh", 1}},
{"two", {"miny", 5}},
{"three", {"asap", 3}}
};
initializer list 생성자
새로운 방식의 { }를 위한 생성자도 만들 수 있다.
생성자를 구현해두면, 다른 생성자보다 initializer list 생성자가 먼저 고려된다.
#include <initializer_list>
#include <iostream>
#include <string>
class A {
public:
A(int x, double y) { std::cout << "일반 생성자! " << std::endl; }
A(std::initializer_list<std::string> lst) {
std::cout << "string 초기화자 사용 생성자! " << std::endl;
}
/*A(std::initializer_list<int> lst) {
std::cout << "int 초기화자 사용 생성자! " << std::endl;
for (auto itr = lst.begin(); itr != lst.end(); ++itr) {
std::cout << *itr << std::endl;
}
}*/
};
A func(void) {
return { "string", "initializer" }; // 리턴도 대입이라 string 초기화생성자 호출
}
int main() {
A a(3, 1.5); // 일반
A b{"abc", "def"}; // string 초기화자
// 기본적으로 일반 초기화지만, 주석을 제거하면 int 초기화자 생성자가 호출된다.
// 그렇게되면 두번째 인자의 소숫점이 손실되어 Narrow Error 가 발생한다.
A c{3, 1.5};
A d = {3, 1.5};
}
auto와 함께 쓰는 { }
c++11
모든 경우 initializer_list
auto a = {1}; // std::initializer_list<int>
auto b{1}; // std::initializer_list<int>
auto c = {1, 2}; // std::initializer_list<int>
auto d{1, 2}; // std::initializer_list<int>
c++17~
auto x = {arg1, arg2, ...}형태의 경우 arg1, arg2 … 가 모두 같은 타입이라면initializer_list<T>로 추론된다.auto x{arg1, arg2, ...}형태의 경우 인자가 한개라면 인자의 타입으로 추론되고, 여러개라면 오류가 발생한다.
auto a = {1}; // auto x = {} 형태 std::initializer_list<int>
auto b = {1, 2}; // 위와 동일
auto c{1}; // auto x{} 형태 이므로 타입추론해서 int
auto d{1, 2}; // auto x{} 형태인데 인자가 2 개 이상이므로 컴파일 오류
Comments