Effective Modern C++ - Scott Meyers
Item 2: Understand auto type deduction.
item 2. auto의 타입 추론을 이해하자.
* Intro
item 1의 template type deduction을 봤다면, auto type deduction에 대해서 거의 모든걸 이해한 것이다. 단, 한가지 중요한 예외사항만 빼놓는다면 말이다.
template type deduction과 auto type deduction은 직접적으로 mapping이 된다.
이번에도 item 1과 같이 아래의 용어를 쓸것임을 미리 밝혀둔다.
template<typename T> // T 는 template에서의 type을 의미
void f(ParamType param); // ParamType은 T로 표현되는 함수정의에 적힌 param의 type
f(expr); // expr은 함수 호출시 사용되는 표현
|
* template type deduction 인듯,
template type deduction 같은 auto type deduction
auto 는 T의 역할을 한다.
auto 앞에 붙은 type 지정자와 auto가 합쳐져서 ParamType이 되는 것이고,
= 오른쪽에 오는 것이 expr이 된다.
auto x = 27; |
template<typename T>
void func_for_x(T param);
func_for_x(27);
|
const auto cx = x; | template<typename T>
void func_for_cx(const T param);
func_for_cx(27);
|
const auto& rx = x; |
template<typename T>
void func_for_rx(const T& param);
func_for_rx(27);
|
item 1에서 3가지 경우에 대해서 template type deduction을 살펴보았다.
Case 1 : ParamType이 Reference (&) 이거나 Pointer (*) 인 경우. 단 Universal Reference (&&)는 제외
Case 2 : ParamType이 Universal Reference (&&)인 경우
Case 3 : ParamType이 그냥 Call-by-Value인 경우
위에 이미 case 1, 3에 대해서는 살펴보았다.
auto x = 27; // case 3
const auto cx = x; // case 3
const auto& rx = x; // case 1
|
auto&& uref1 = x; // x : lvalue -> uref1 : int&
auto&& uref2 = cx; // cx : lvalue -> uref2 : const int&
auto&& uref3 = 27; // 27 : rvalue -> uref3 : int&&
|
const char str[] = "Luna the Star"; // str's type is const char[14]
auto a1 = str; // const char *a1
auto& a2 = str; // const char (&a2)[14]
void someFunc(int, double);
auto f1 = someFunc; // void (*f1)(int, double);
auto& f2 = someFunc; // void(&f2)(int, double);
|
*
template type deduction 아닌,
이제부터는 template type deduction과는 다르게 동작하는 auto type deduction에 대해서 살펴볼 것이다.
int x1 = 27;
int x2(27);
int x3 = {27};
int x4{27};
|
위 4개의 code에 대해서 모두 27로 초기화된 int란 것이라고 알 수 있다.
그럼 int에서 auto로 바꾸면 어떤일이 벌어질까 ?
auto x1 = 27; // type : int, value : 27
auto x2(27); // type : int, value : 27
auto x3 = { 27 }; // type : std::initializer_list<int>, value { 27 }
auto x4{ 27 }; // type : std::initializer_list<int>, value { 27 }
|
물론 아래와 같은 초기화는 Compile에서부터 error가 발생한다.
auto x5 = { 1, 2, 3.0 }; // error! can't deduce T for std::initializer_list<T> |
1. Uniform Initialization을 사용할 때는 std::initializer_list<T> 로 추론된다.
2. 그런 다음 T에 대하여 template type deduction을 해야하는데,
{ } 안에 서로 다른 2가지 이상의 type이 있으면 오류가 발생한다.
auto 에는 특별한 type deduction 규칙이 있다. 방금 위에 써놓고 이말을 왜 또 하냐고 ?
template에는 이 특별한 type deduction이 없다. 이말을 하고 싶어서 한 번 더 언급하였다.
auto x = { 1977, 7, 26 }; // std::initializer_list<int>
template<typename T>
void f(T param);
f({ 1977, 7, 26 }); // error C2784: can't deduce template argument for 'T' from initializer-list
|
template 의 T는 Uniform Initialization을 std::initializer_list<T> 로 추론을 못한다.
이 문제를 해결할려면 ParamType 자체를 바꿔줘야 한다.
template<typename T>
void f(std::initializer_list<T> param);
f({ 1977, 7, 26 }); // T : int, ParamType : std::initializer_list<int>
|
하지만 여기에 사용된 auto는 auto type deduction이 아닌 template type deduction이 적용된 것으로 보인다.
auto LunasBirthday()
{
return { 1977, 7, 26 }; // error C3108 : can't deduce a type as an initializer-list is not an expression
// error C2440 : 'return' : can't convert from 'initializer_list' to 'auto'
}
|
하지만 여기에 사용된 auto는 auto type deduction이 아닌 template type deduction이 적용된 것으로 보인다. (어디선가 본 문장 같은데...)
std::vector<int> v;
auto LunasBirthday = [&v](const auto& d) { v = d};
LunasBirthday({ 1977, 7, 26 });// error : can't deduce a type for initializer-list
|
아쉽게도 Visual Studio 2015에서는 Lambda의 parameter로 아직 auto가 허용되지 않는다.
Things to Remember * auto type deduction은 거의 template type deduction과 같다. 하지만 auto type deduction에서는 Uniform Initialization을 이용하면 (무조건) std::initializer_list<T>로 초기화가 되는데, template type deduction에서는 오류가 발생한다. * C++ 14에 추가된 auto의 사용법 중 return type의 auto 와 Lambda의 parameter에 사용된 auto는 auto type deduction이 아닌 template type deduction 규칙을 따른다. |
댓글 없음:
댓글 쓰기