C++ 중급 - Type Deduction 1

타입·2024년 2월 19일

C++ 공부

목록 보기
10/17

Type Deduction(추론)

컴파일러가 주어진 조건(표현식)을 가지고 타입을 결정하는 과정

  • Type Deduction이 발생하는 경우
    • template
    • auto
    • decltype
  • 추론된 타입을 조사하는 방법
  1. typeid(T).name()
    const, volatile, reference 정보가 출력되지 않음
  2. 에러 메시지 확인
    의도적으로 에러를 발생시키면 에러 메시지 안에서 타입 확인 가능
  3. boost::type_index 라이브러리 사용
    type_id_with_cvr< T >().pretty_name()
  4. 컴파일러가 제공하는 함수 이름을 담은 매크로 사용
__FUNCTION__: C++ 표준, 함수 이름만 나타냄
__PRETTY_FUNCTION__: 인자와 반환 값을 나타냄 (g++, clang++)
__FUNCSIG__: 인자와 반환 값을 나타냄 (Visual Studio, cl.exe)

Template Type Deduction

  • Template Type Deduction에서 알아야 하는 것
    T arg: 인자를 값으로 받을 때
    T& arg: 인자를 lvalue reference로 받을 때
    T&& arg: 인자를 rvalue reference로 받을 때
    인자로 배열이 전달 될 때

  • T를 값으로 받을 때

template<typename T> void foo(T arg)
{
	while (--arg > 0 ) {}
}

int main()
{
    int n = 10;
    int& r = n;
    const int c = 10;
    const int& cr = c;

    foo(n); // T=int
    foo(r); // T=int
    foo(c); // T=int
    foo(cr);// T=int
}
  • 규칙 1
    Template 인자를 값(T arg)으로 받을 때
    새로운 복사본 객체가 만들어져서 값을 복사 받는 것
    함수 인자의 const, volatile, reference를 제거하고 T의 타입을 결정
    인자의 const 속성만 제거되고, 인자가 가리키는 곳의 const 속성은 유지
int main()
{
    const char* const s = "hello";
    // s는 상수 포인터이므로 포인터의 const 속성이 제거
    foo(s); // T=const char*
}

  • T를 참조로 받을 때
template<typename T> void foo(T& arg)
{
}

int main()
{
    int n = 10;
    int& r = n;
    const int c = 10;
    const int& cr = c;

    foo(n); // T=int        arg=int&
    foo(r); // T=int        arg=int&
    foo(c); // T=const int  arg=const int& // 상수 객체는 상수 참조로만 가리킬 수 있음
    foo(cr);// T=const int  arg=const int&
}
  • 규칙 2
    Template 인자를 lvalue reference(T& arg)로 받을 때
    T의 타입과 arg의 타입은 다름
    함수 인자의 reference를 제거하고 T의 타입을 결정
    인자가 가진 const, volatile 속성은 유지

  • T를 배열로 받을 때

template<typename T> void foo(T arg) // T arg = x
{   
	//int arg[3] = x; // 이렇게 추론되면 컴파일 에러이므로
	//int* arg = x; // T를 포인터로 추론
}
template<typename T> void goo(T& arg)// T& arg = x
{
    //int(&arg)[3] = x; // 배열을 가리키는 참조, arg가 x를 가리킴
}
int main()
{
    int x[3] = {1,2,3};
    foo(x);
    goo(x);
}
  • 템플릿 인자로 배열을 전달할 때
    T arg - T는 포인터 (int*)
    T& arg - T는 배열 (int[3]), arg는 배열을 가리키는 참조 (int(&)[3])
template<typename T> void foo(T s1, T s2)
{
    // T가 char*로 바껴서 같은 타입
}
template<typename T> void goo(T& s1, T& s2)
{
	// T가 const char[7], const char[6]로 서로 달라 컴파일 에러
}
int main()
{
    foo("orange", "apple"); // ok
    // foo(const char[7], const char[6])

//	goo("orange", "apple"); // error
    // goo(const char[7], const char[6])
 
    goo("orange", "banana"); // 글자의 개수가 같아 컴파일 성공
}

Auto Type Deduction

template: 함수 인자로 타입 추론 (T arg = 함수인자;)
auto: 우변의 표현식으로 타입 추론 (auto a = 표현식;)

템플릿 규칙과 동일

int main()
{
    int n = 10;
    int& r = n;
    const int c = 10;
    const int& cr = c;

    // 규칙 1.
    auto a1 = n; // auto=int
    auto a2 = r; // auto=int
    auto a3 = c; // auto=int
    auto a4 = cr;// auto=int

    // 규칙 2.
    auto& a5 = n; // auto=int           a5=int&
    auto& a6 = r; // auto=int           a6=int&
    auto& a7 = c; // auto=const int     a7=const int&
    auto& a8 = cr;// auto=const int     a8=const int&

    int x[3] = {1,2,3};
    auto  a = x; // auto=int* 
    auto& b = x; // auto=int[3]  b = int(&)[3]
}
  • auto 사용 시 주의사항
int main()
{
    auto a1 = 1;	// int
    auto a2 = {1};	// std:initializer_list<int>
    auto a3{1};		// int
    
    std::vector<int>  v1(10,0);
    std::vector<bool> v2(10,false); // bool(1byte)을 10개를 보관하지 않고 10bit 보관

    auto a4 = v1[0]; // int
    auto a5 = v2[0]; // proxy객체 (bool이 아님!)
}
  • std::vector<bool>
    최적화를 위해 Specialization 되어 있음
    [] 연산자가 bool로 변환 가능한 Temporary proxy를 반환
profile
주니어 언리얼 프로그래머

0개의 댓글