배고픈 개발자 이야기
[Effective Modern C++] Chapter 1 - Item2 요약 본문
Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14
Meyers, Scott |
Item 2 : Understand auto type deduction
auto 타입 추론 = 템플릿 타입 추론 (Direct Mapping)
template<typename T>
void f(ParamType param);
f(expr); // call f with some expression
auto x = 27;
const auto cx = x;
const auto& rx = x
auto = 템플릿의 T역할, 타입 지정자 = ParamType 역할
template<typename T> // conceptual template for
void func_for_x(T param); // deducing x's type
func_for_x(27); // conceptual call: param's
// deduced type is x's type
template<typename T> // conceptual template for
void func_for_cx(const T param); // deducing cx's type
func_for_cx(x); // conceptual call: param's
// deduced type is cx's type
template<typename T> // conceptual template for
void func_for_rx(const T& param); // deducing rx's type
func_for_rx(x); // conceptual call: param's
// deduced type is rx's type
Item 1에서 템플릿 타입 추론을 세 경우로 나눠서 살펴봤음.
- Case 1 : 타입 지정자가 포인터 또는 레퍼런스인 경우
- Case 2 : 타입 지정자가 유니버셜 레퍼런스인 경우
- Case 3 : 타입 지정자가 포인터 또는 레퍼런스가 아닌 경우
const auto cx = x; // case 3 (cx isn't either)
const auto& rx = x; // case 1 (rx is a non-universal ref.)
auto&& uref2 = cx; // cx is const int and lvalue, so uref2's type is const int&
auto&& uref3 = 27; // 27 is int and rvalue, so uref3's type is int&
이처럼 auto 타입 추론 = 템플릿 타입 추론. 단 한 가지 예외 사항이 있음.
- 초기값 27을 가지는 int 변수를 선언하고 싶다고 가정.
- C++ 98에서는 두 가지 문법을 제공했었음.
int x1 = 27;
int x2(27);
- C++ 11에서는 유니폼 초기화(Uniform Initalization)을 지원함.
int x3 = {27};
int x4{27};
앞에서 x1, x2, x3, x4의 타입은 전부 int.
하지만 auto로 바꾸면 사정이 달라짐.
auto x1 = 27; // type is int, value is 27
auto x2(27); // ditto
auto x3 = { 27 }; // type is std::initializer_list<int>, value is { 27 }
auto x4{ 27 }; // ditto
auto에는 특별한 타입 추론 규칙이 있음.
- auto로 선언된 변수에 유니폼 초기화를 사용할 때, 추론된 타입은 std::initializer_list가 됨.
- 만약 추론할 수 없는 타입이면, 오류가 발생함.
auto x5 = {1, 2, 3.0} // 서로 다른 타입, std::initializer_list<T>로 추론할 수 없음
실제로 두 종류의 타입 추론이 일어남.
1. auto의 사용으로 인해 x5의 타입이 std::initializer_list로 추론됨.
2. std::initializer_list는 템플릿이므로 타입 T에 대해 std::initializer_list<T>로 인스턴스화가 일어남. 즉, T의 타입에 대해서도 추론이 일어남.
auto 타입 추론과 템플릿 타입 추론의 차이{}에 대해 auto타입 추론은 std::initializer_list로 추론하고, 템플릿 타입 추론은 그렇지 않다는 것!
auto x = {11, 23, 9} // x의 타입은 std::initializer_list<int>
template<typename T> // 매개변수가 있는 템플릿의 선언은 x의 선언와 동일함.
void f(T param);
f({11, 23, 9}); // 오류! T의 타입을 추론할 수 없음.
하지만 템플릿의 매개변수를 std::initializer_list<T>로 지정하면, 템플릿 타입 추론은 T가 무엇인지 추론할 수 있음.
template<typename T>
void f(std::initializer_list<T> initList);
f({11,23, 9}); // T는 int로 추론
// initList의 타입은 std::initializer_list<int>
C++14에서는 함수의 리턴 타입에 auto를 사용해 추론 가능.
- auto 타입 추론이 아닌 템플릿 타입 추론을 이용함.
auto createInitList()
{
return { 1, 2, 3 }; // error: can't deduce type
} // for { 1, 2, 3 }
C++14에서는 람다식에서 매개변수 선언 시 auto 사용 가능.
- auto 타입 추론이 아닌 템플릿 타입 추론을 이용함.
std::vector<int> v;
…
auto resetV = [&v](const auto& newValue) { v = newValue; }; // C++14
…
resetV({ 1, 2, 3 }); // error! can't deduce type for { 1, 2, 3 }
Summary
- 일반적으로 auto 타입 추론은 템플릿 타입 추론과 같다. 하지만 auto 타입 추론은 유니폼 초기화를 사용한 경우 std::initializer_list를 나타낸다고 가정하지만, 템플릿 타입 추론은 그렇지 않다.
- 함수의 리턴 타입이나 람다식의 매개변수로 사용하는 auto는 auto 타입 추론이 아닌 템플릿 타입 추론을 암시한다.
reference by https://devsong.tistory.com/121
'언어 > Effective Mordern C++' 카테고리의 다른 글
[Effective Mordern C++] Chapter 1 - Item3 ~ Item6 (0) | 2019.10.27 |
---|---|
[Effective Modern C++] Chapter 1 - Item 1 요약 (0) | 2019.10.08 |
[Effective Modern C++] 0.소개 (0) | 2019.10.07 |