본문 바로가기
Language/effective modern C++

Effective modern C++ ( 형식 언어 )

by y.j 2021. 9. 21.
728x90

형식 연역

항목 1: 템플릿 형식 연역 규칙을 숙지하라

필요성 : 템플릿 형식 연역 규칙들이 auto의 문액에 적용 될 때 덜 직관적임
auto를 잘 활용하려면 템플릿 형식 연역을 이해하고 있어야 한다.

T, ParamType서로 다르게 연역된다.

template<typename T>
void f(ParamType param)

f(expr)

*위의 식은 아래에서 parameter를 말하기 위해서 사용한다.

  1. 보편 참조(universal reference)가 아닌 경우 ( 포인터 or 참조 형식 )
    1. 만일 expr이 참조 형식이면 참조 부분을 무시
    2. expr의 형식을 ParamType에 대해 패턴 부합(pattern-matching)방식으로 대응시켜 T의형식을 결정
template<typename T>
void f(T& param);

int x = 27;
const int cx = x;
const int& rx = x;

f(x);                  // T는 int, 
                       // param의 형식 int&

f(cx);                 // T는 const int, 
                       // param의 형식은 const int&

f(rx);                 // T는 const int,
                       // param의 형식은 const int&

한정사는 T에 연역되기 때문에 const를 붙이지 않아도 안전하다. (둘째, 셋째)
변수의 참조성은 무시된다. (셋째)

template<typename T>
void f(const T& param);

int x = 27;
const int cx = x;
const int& rx = x;

f(x);                  // T는 int, 
                       // param의 형식 const int&

f(cx);                 // T는 int, 
                       // param의 형식은 const int&

f(rx);                 // T는 int,
                       // param의 형식은 const int&

const T&로 바꾸었을 때,
이미 param이 const에 대한 참조로 되어 있기 때문에 연역 될 필요가 없다.

template<typename T>
void f(T* param);

int x = 27;
const int *px = &x;

f(&x);                  // T는 int,
                        // param의 형식 int*

f(cx);                 // T는 const int, 
                       // param의 형식은 const int*

이미 Param 포인터이기 때문에 T에 연역 될 필요가 없다.

  1. ParamType이 보편 참조인 경우
    만일 expr이 l-value이면, T와 ParamType 둘다 l-value참조로 연역된다.
  2. r-value이면, 1의 경우와 같다.
template<typename T>
void f(T&& param);

int x = 27;  
const int cx = x;  
const int& rx = x;

f(x); // T는 int&,  
      // param의 형식 int&

f(cx); // T는 int&,  
       // param의 형식은 int&

f(rx); // T는 int&,  
       // param의 형식은 int&

f(27); // T는 int  
       // param의 형식은 int&&
  1. ParamType이 보편 참조, 포인터 둘다 아닌 경우
    1. expr의 참조를 무시한다.
    2. const/volatile도 무시한다.
template<typename T>
void f(T param);


int x = 27;  
const int cx = x;  
const int& rx = x;

f(x); // T는 int,  
// param의 형식 int

f(cx); // T는 int,  
// param의 형식은 int

f(rx); // T는 int,  
// param의 형식은 int

const char* const ptr은 ptr을 const로 받기 때문에 수정이 가능하지 않은 ptr이므로 문자를 바꿀 수 없다.
하지만 연역하는 동안은 const ptr의 const는 연역이 되면서 사라지게 된다.

template<typename T>
void f(T param);

const char * const ptr = "Fun with Pointer";

f(ptr); // const char \* const 형식의 인수를 전달  

배열 인수

배열형식과 포인터 형식은 다르기 때문에 배열이 배열을 가르키는 첫 원소로 붕괴하기 때문이다.
아래와 같은 경우 설명에서 말한 붕괴 법칙 때문에 잘 컴파일 된다.

 const char name[] = "J. P. Briggs"; // const char[13]

 const char * ptrToName = name;      // 배열이 포인터로 붕괴된다.

 void myFunc(int param[]);           // 위 아래 코드는 동치이기 때문에 1번 규칙을 적용받는다.
 void myFunc(int* param); 

함수 인수
함수형식도 함수 포인터로 붕괴가 가능하다.

 void someFunc(int, double);  

 template<typename T>
 void f1(T param);

 template<typename T>
 void f2(T& name);

 f1(someFunc);              // param은 함수 포인터로 연역됨

 f2(someFunc);              // param은 함수 참조로 연역됨
728x90

댓글