[Modern C++] Type Deduction - decltype

Program Lang./C++ 2019. 7. 29. 15:35

1. decltype type deduction

 

decltype의 사용형식은 다음과 같다.

 

  • decltype(expr) n

 

expr의 표현식의 따라서 type deduction은 크게 두가지로 분류될 수 있다.

 

  • expr에 연산자가 존재하지 않을 경우의 type deduction
  • expr에 연산자가 존재할 경우의 type deduction

 

2. expr에 연산자가 존재하지 않는 경우

 

expr에 연산자가 존재하지 않으면, expr과 동일한 type으로 변환된다.

 

1
2
3
4
5
6
const int i = 0;
decltype(i) n;  // const int 과 동일
 
bool f(const Widget& w);
decltype(w) n;  // const Widget& 과 동일
decltype(f) n;  // bool(const Widget&) 과 동일

 

3. expr에 연산자가 포함되어 있는 경우

 

expr에 연산자가 존재하면, expr이 lvalue냐 또는 rvalue냐를 식별해야 한다.

lvalue일 경우, reference가 붙지만 rvalue이면 reference는 붙이지 않는다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int n = 10;
int *p = &n;
decltype(p) a;  // no operation in expr, decltype(p)는 int*
decltype(*p) a; // *p : lvalue, decltype(*p)는 int&
 
int x[3] = {1, 2, 3}
decltype(x[0]) a;   // x[0] : lvalue, lvalue, decltype(x[0])는 int&
 
vector<int> v {1, 2, 3};
decltype(v[0]) a; // v[0] : lvalue, lvalue, decltype(v[0])는 int&
 
// rvalue case
decltype(n + n) a;  // n + n 는 rvalue, decltype(n + n)는 int
decltype(n++) a;    // n++ 는 rvalue, decltype(n++)는 int

 

4. decltype(auto) 정리

 

c++14부터 지원하는 문법이다. 정확한 의미는 다음과 같다.

  • auto
    • type deduction이 필요하다.
  • decltype
    • type deduction rule은 decltype의 rule을 따른다.

결론적으로 type deduction을 수행해야 하는데, 이 때 decltype의 rule을 따른다의 의미이다.

이 형식이 어디에 사용되느냐는 함수의 return type과 관련이 있다.

Effective Modern C++의 추가 내용들은 perfact forwarding과 관련된 부분이 대부분이라서

간단히 왜 이런 구문이 나왔는지 측면에서 정리하고 넘어간다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
// c++11 코드
template<typename C, typename I>
auto authAndAccess(C& c, I i) -> decltype(c[i])
{
    return c[i];
}
 
// 위와 동일한 c++14 코드
template<typename C, typename I>
auto authAndAccess(C& c, I i)
{
    return c[i];

 

위의 코드에서 함수의 return을 auto로 받고 있다. auto의 type deduction에서 기술하였듯이

함수의 return type의 auto의 경우 template의 type deduction 규칙을 따른다.

이 경우 return되는 c[i]는 C&이지만 auto의 type deduction이 template 규칙을 따르기 때문에

최종적으로 return type은 C가 된다.

 

이 경우 문제는 다음과 같은 코드에서 문제가 발생할 수 있다.

 

std::deque<int> d;

authAndAccess(d, 5) = 10;

 

authAndAccess()의 return type은 rvalue를 return하고 있어서 대입 시 에러가 발생한다.

 

여기서 해결책은 무엇인가? c++11의 경우에는 perfact forwarding에 대한 지식이 필요하므로

c++14 기준으로 해결책은 decltype(auto)로 return type을 바꾸는 것이다.

decltype(auto)의 의미에 따라서 C&로 return type이 결정된다.

 

1
2
3
4
5
6
// authAndAccess의 return type을 C&로 받기 위한 해결책
template<typename C, typename I>
decltype(auto) authAndAccess(C& c, I i)
{
    return c[i];

 

5. 정리

 

decltype의 type deduction은 expr의 표현식의 연산자 유무에 따라서 그 동작에 차이가 있다.

이 부분을 주의해서 사용하는 것이 핵심이고, decltype(auto)는 양념정도로 알아두면 좋을 듯 하다.

: