decltype
- 식별자 표현식이 아닌 식을 인자로 받고, 그 타입을 T라고 했을 때
- 식의 값이 xvalue인 경우 -> T&& 를 리턴
- 식의 값이 lvalue인 경우 -> T& 를 리턴
- 식의 값이 prvalue인 경우 -> T 를 리턴
- decltype 안에 식이 존재하더라도, 컴파일 타임에 전부 식으로 치환
int a, b;
decltype(a+b) c; // c -> int 타입
// &(A)로 주솟값 추론 가능
// (A)의 값 이동 불가능
// lvalue
int A;
decltype((A)) B; // B -> int& 타입
쓰임새
- 대체재일 수 있는 auto
- 그러나 auto는 타입을 정확하게 변형해주지 않는다
- decltype은 정확하게 해준다
// ex1
const int i = 4;
auto j = i; // int j = i;
decltype(i) k = i; // const int k = 4;
// ex2
int arr[4];
auto arr2 = arr; // int* arr2 = arr;
decltype(arr) arr3; // int arr3[4];
- 탬플릿 함수에서 결과값의 타입이 달라지는 경우
// * 아래의 식은 컴파일 에러를 발생한다
// T t 와 U u 이전에 t+u가 나오기 때문
template <typename T, typename U>
decltype(t + u)* add (T t, U u)
{
// T가 int이고 U가 double인 경우, 리턴 타입은 double*가 된다
return t + u;
}
// 수정본
template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u) {
return t + u;
}
std::declval
// 어떤 클래스 T는 (= B)
// 가본 생성자를 선언하지 않았다
template <typename T>
decltype (T().f()) func(T& t)
{
return t.f();
}
// A는 컴파일러에 의해 자동 생성
struct A
{
int f() {return 0;}
}
// B는 copy constructor에 의해 자동생성되지 않음
struct B
{
B (int x) {}
int f() {return 0;}
}
int main() {
A a;
B b(1);
func(a); // ok
func(b); // BAD
}
#include <utility>
// 어떤 클래스 T는 (= B)
// 여전히 가본 생성자를 선언하지 않았고
// 우리는 std::declval을 사용한다
template <typename T>
decltype (std::declval<T>().f()) func(T& t)
{
return t.f();
}
struct A
{
int f() {return 0;}
}
struct B
{
B (int x) {}
int f() {return 0;}
}
int main() {
A a;
B b(1);
func(a); // ok
func(b); // ok
}
별첨
- C++14부터 리턴 타입에 auto를 써 컴파일러가 타입을 추측하는 기능이 추가
template <typename T>
auto func(T& t) {
return t.f();
}
출처