C++ 아이콘 제작자: Darius Dan - Flaticon
식별자 표현식이란 변수의 이름, 함수의 이름, enum 이름, 클래스 멤버 수(a.b 나 a->b같은 꼴) 등을 의미한다.
==> 쉽게 생각하면 어떠한 연산을 하지 않고 단순히 객체 하나만을 가리키는 식
- 그렇다면 만약에 decltype 에 식별자 표현식이 아닌 식을 전달하면 어떻게 될까??
해당 식의 값의 종류(value category)에 다르다
- 만일 식의 값 종류가 xvalue 라면 decltype 는 T&&
- 만일 식의 값 종류가 lvalue 라면 decltype 는 T&
- 만일 식의 값 종류가 prvalue 라면 decltype 는 T
int a, b;
decltype(a + b) c; // c 의 타입은?
==> a + b 는 prvalue 이므로 a + b 식의 실제 타입인 int 로 추론
int a;
decltype((a)) b; // b 의 타입은?
==> 우선 (a) 는 식별자 표현식이 아니다
==> 쉽게 생각하면 &(a) 와 같이 주소값 연산자를 적용할 수 있고, 당연히도 이동 불가능 이므로 lvalue되므로
==> int& 로 추론된다.
const int i = 4;
auto j = i; // int j = i;
decltype(i) k = i; // const int k = i;
또 배열의 경우 auto 는 암시적으로 포인터로 변환하지만
decltype 의 경우 배열 타입 그대로를 전달한다int arr[10]; auto arr2 = arr; // int* arr2 = arr; decltype(arr) arr3; // int arr3[10];
template <typename T, typename U>
void add(T t, U u, /* 무슨 타입? */ result) {
*result = t + u;
}
result의 타입이 t+u 결과에 의해 결정된다
여기에서 result 타입에 decltype을 사용하면 된다.
template <typename T, typename U>
void add(T t, U u, decltype(t + u)* result) {
*result = t + u;
}
template <typename T, typename U>
decltype(t + u) add(T t, U u) {
return t + u;
} // 컴파일 오류!!
컴파일러가 decltype에 있는 t와 u를 알지 못한다.
t와 u가 정의된 후에 사용해야 하기 때문이다.
하지만 C++ 14 부터 추가된 아래와 같은 문법으로 구현 가능template <typename T, typename U> auto add(T t, U u) -> decltype(t + u) { return t + u; }
람다 함수와 비슷하게 생겼는데 리턴 타입에는 auto를 쓰고 -> 뒤에 실제 리턴 타입을 기입
만약 어떤 클래스의 멤버 함수의 리턴값을 알고싶어 decltype을 사용했다고 생각하자.
그런데 해당 함수에 생성자가 없으면 컴파일 오류가 발생할 것이다.
decltype(A().func()) what_type;
==> A() 생성자가 없으면 컴파일 오류 발생
declval 함수를 타입 연산에서만 사용해야지, 실제로 런타임에 사용하면 오류가 발생
B b = std::declval<B>();
참고로 C++ 14 부터는 함수의 리턴 타입을 컴파일러가 알아서 유추해주는 기능이 추가되었다.
이 경우 그냥 함수 리턴 타입을 auto 로 지정해주면 된다template <typename T> auto call_f_and_return(T& t) { return t.f(); }
개인 공부 기록용 블로그입니다.
틀린 부분 있으다면 지적해주시면 감사하겠습니다!!