1 분 소요

1. 정의

<utility> 에 정의된 함수 std::declval

컴파일타임 때 타입을 전달하면 해당 타입의 생성자를 직접 호출하지 않더라도 생성된 객체를 나타낼 수 있다

동작을 들어도 잘 이해가 되지 않기 때문에 예제를 참고        

2. 예제

문제상황

decltype을 이용해서 특정타입의 특정함수가 반환하는 값을 template으로 명시할 수 있다

이것을 이용해서 들어온 T타입의 f함수를 호출하고 그 결과를 return 하는 함수를 만들어보면 다음과 같다

//T타입의 f함수의 결과 타입을 반환하는 함수
//decltype으로 f()로 명시되어있어서 반환타입을 명시할 수는 있지만
//인자값이 없는 함수만 작동
template <typename T>
decltype(T().f()) call_f_and_return(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);

	call_f_and_return(a);  // ok
	call_f_and_return(b);  // BAD
}

디버그 에러 발생

해당 코드는 에러가 발생한다 T().f() 부분에서 struct A는 상관이 없지만 struct B는 인자없는 기본 생성자가 없기 때문에 컴파일 타임 때 실패한다

   

declval을 통해 해결

#include <utility>

//T타입의 f함수의 결과 타입을 반환하는 함수
template <typename T>
decltype(std::declval<T>().f()) call_f_and_return(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);

	call_f_and_return(a);  // ok
	call_f_and_return(b);  // ok
}

declval을 사용하면 해당 생성자가 없다고 해도 마치 있는 것처럼 작동시킬 수 있다

C++14부터는 더 간단하게 가능

template <typename T>
auto call_f_and_return(T& t)
{
	return t.f();
}

하지만 이 이외에 Type Traits에서도 많이 사용됨

댓글남기기