[Modern C++] 항목 2: auto의 형식 연역 규칙을 숙지하라
카테고리: Cpp
이 글은 아래의 책을 정리하였습니다. 이펙티브 모던 C++, 스콧 마이어스 저자, 류광 번역
📦 1. 형식 연역
👉🏻 항목 2: auto의 형식 연역 규칙을 숙지하라
- 들어가기 앞서, auto 형식 연역과 템플릿 형식 연역이 따로 있다는 것을 기억하자.
auto는 템플릿 형식 연역과 매우 비슷하다.- 하지만, 한 가지 예외는 있다.
auto x = 27; // 형식 지정자 = auto
const auto cx = x; // 형식 지정자 = const auto
const auto& rx = x; // 형식 지정자 = const auto&
auto는 템플릿의T와 동일한 역할- 변수의
형식 지정자는ParamType과 동일한 역할
📌 연역 형태에 따른 3가지 경우
형식 지정자가 포인터/참조 형식이지만, 보편 참조는 아닌 경우형식 지정자가 보편 참조인 경우형식 지정자가 포인터/참조 형식이 아닌 경우
auto x = 27; // ③ 형식 지정자 = auto
const auto cx = x; // ③ 형식 지정자 = const auto
const auto& rx = x; // ① 형식 지정자 = const auto&
// ② x는 왼값
auto&& uref1 = x; // ∴ 형식 = int&
// ② cx는 왼값
auto&& uref2 = cx; // ∴ 형식 = const int&
// ② 27는 오른값
auto&& uref3 = 27; // ∴ 형식 = int&&
// 포인터 붕괴
const char name[] = "R. N. Briggs"; // 형식 = const char[13]
auto arr1 = name; // 형식 = const char*
auto& arr2 = name; // 형식 = const char(&)[13]
void someFunc(int, double); // 형식 = void(int,double)
auto func1 = someFunc; // 형식 = void(*)(int,double)
auto& func2 = someFunc; // 형식 = void(&)(int,double)
auto의 형식 연역은 템플릿 형식 연역과 똑같이 작동한다.
⚠️ 한 가지 다른 점
// 자료형이 int
int x1 = 27; // 형식 = int
int x2(27); // 형식 = int
int x3 = { 27 }; // 형식 = int
int x4{ 27 }; // 형식 = int
// 자료형이 auto
auto x1 = 27; // 형식 = int
auto x2(27); // 형식 = int
auto x3 = { 27 }; // 형식 = std::initializer_list<int>
auto x4{ 27 }; // 형식 = std::initializer_list<int>
- C++11에서는 위처럼 값이 27인
int변수를 생성할 수 있다. auto로 바꾸면, 특별한 형식 연역 규칙으로 인해 차이점이 생긴다.
// ⚠️ 오류! 중괄호 초기치를 구성하는 값들이 한 종류가 아니므로
// std::initializer_list<T>의 T를 연역할 수 없음!
auto x5 = { 1, 2, 3.0 };
// ✅ std::initializer_list<int>로 auto 형식 연역
auto x = { 11, 23, 9 };
- 변수 초기화를 중괄호 쌍으로 감싸면 형식이
std::initializer_list<int>로 연역된다.- 연역할 수 없다면, 컴파일이 거부된다.
연역 과정:
x5의 auto 형식 연역을 먼저 진행하고,auto→std::initializer_list로 연역됨std::initializer_list<T>에 있는T를 템플릿 형식 연역- ∵
std::initializer_list는 하나의 템플릿이기 때문
- ∵
// auto 형식 연역
auto x = { 11, 23, 9 }; // ✅ std::initializer_list로 연역
// 템플릿 형식 연역
template<typename T>
void f(T param);
// ⚠️ 오류! T에 대한 형식을 연역할 수 없음!
f({ 11, 23, 9 });
// param의 형식을 std::initializer_list<T>로 작성해야 함
template<typename T>
void f(std::initializer_list<T> initList);
// ✅ T = int, initList 형식 = std::initializer_list<int>
f({ 11, 23, 9 });
- auto 형식 연역과 템플릿 형식 연역의 차이:
auto는 중괄호 초기치가std::initializer_list를 나타낸다고 가정- 템플릿 형식 연역은 그렇게 가정하지 않음
- auto 형식 연역에서의 과정 1번이 빠지고, 과정 2번만 존재
// ⚠️ 오류! 함수 반환 형식이 auto인 경우,
// 템플릿 형식 연역 규칙 적용!
auto createInitList() {
return { 1, 2, 3 };
}
// ⚠️ 오류! 람다 매개변수가 auto인 경우,
// 템플릿 형식 연역 규칙 적용!
std::vector<int> v;
// C++14
auto resetV = [&v](const auto& newValue) { v = newValue; };
resetV({ 1, 2, 3 });
- 함수 반환 형식 / 람다 매개변수가
auto인 경우, 템플릿 형식 연역 규칙이 적용된다.- ∴ 컴파일 실패
🧐 정리
- auto 형식 연역은 대체로 템플릿 형식 연역과 같다.
- auto 형식 연역은 중괄호 초기치를
std::initializer_list로 가정한다. - 템플릿 형식 연역은 그렇게 가정하지 않는다.
- auto 형식 연역은 중괄호 초기치를
- 함수 반환 형식 / 람다 매개변수가
auto인 경우:- auto 형식 연역 규칙이 아닌, 템플릿 형식 연역 규칙이 적용된다.
댓글남기기