[Modern C++] 항목 2: auto의 형식 연역 규칙을 숙지하라

게시:     수정

카테고리:

태그: ,

이 글은 아래의 책을 정리하였습니다. 이펙티브 모던 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가지 경우

  1. 형식 지정자가 포인터/참조 형식이지만, 보편 참조는 아닌 경우
  2. 형식 지정자가 보편 참조인 경우
  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>로 연역된다.
    • 연역할 수 없다면, 컴파일이 거부된다.

연역 과정:

  1. x5auto 형식 연역을 먼저 진행하고, autostd::initializer_list로 연역됨
  2. 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 형식 연역 규칙이 아닌, 템플릿 형식 연역 규칙이 적용된다.

Cpp 카테고리 내 다른 글 보러가기

댓글남기기