티스토리 뷰

decltype 이라는 키워드는 객체가 주어졌을때, 그 객체의 타입을 알려준다. 예시를 보자.

const int i = 0;  // decltype(i)는 const int
MyClass object;   // decltype(object)는 MyClass

위와 같이 객체의 타입을 알려주는데, 가끔 생각한대로 동작하지 않는 경우가 있다.

 

특이한 작동 방식

먼저 코드를 보자.

template<typename Container, typename Index>
auto authAndAccess(Container& c, Index i) -> decltype(c[i])
{
    authenticateUser();
    return c[i];
}

위에서 보이는 함수처럼 auto decltype 을 이용한 방식을 후행 반환 형식이라고 한다. 후행 반환 형식으로 선언한 함수의 반환 타입은 decltype 에 주어진 객체의 타입이 된다. 여기서는 c[i] 의 타입이다.

 

그런데 만약 c[i] 의 반환 타입이 T& 인 경우라면 생각한대로 동작하지 않는다. 그 이유는 항목 1형식 연역 규칙 3에 의해 참조성이 사라지기 때문이다. 

 

형식 연역을 위한 decltype(auto)

위 코드의 문제를 해결하는 방법은 아주 간단하다. decltype auto 를 합치면 된다. decltype(auto) 는 말 그대로 auto 로 형식을 연역하는데 그 과정에서 decltype의 규칙을 사용하겠다는 의미다. 문제를 수정한 코드는 다음과 같다.

template<typename Container, typename Index>
decltype(auto)
authAndAccess(Container& c, Index i)
{
    authenticateUser();
    return c[i];
}

이 코드는 앞서 이야기한 문제를 해결한다. 하지만 두가지 문제점이 존재한다. 하나는 Container 가 우측값으로 넘어오는 경우이고 나머지 하나는 아주 예외적인 경우이다.

 

우측값 참조를 위한 보편참조

위의 코드에서 c는 우측값으로 넘어 올 수 없다. c[i] 가 참조인 경우 Container const 로 지정될 수 없기 때문이다. 이때 사용하는 방법이 바로 보편참조이다. Container& c 파라미터를 Container&& c 로 바꾸기만 하면 된다. 최종 완성코드는 다음과 같다.

template<typename Container, typename Index>
decltype(auto)
authAndAccess(Container&& c, Index i)
{
    authenticateUser();
    return std::forward<Container>(c)[i];
}

forward move 와 비슷한 함수로 항목 25를 참고하자.

두번째 특이한 예외 상황

두번째로 생길 수 있는 문제는 코드로 확인하자.

decltype(auto) f1()
{
	int x = 0;
    ...
    return x;
}

decltype(auto) f2()
{
	int x = 0;
    ...
    return (x);
}

f1과 f2는 똑같은 함수처럼 보인지만 반환 타입은 다르다. 첫번째는 int 타입이지만 두번째는 int& 가 된다. 위와 같이 사용하는 경우는 없겠지만 decltype은 조심히 사용해야 함을 잊지 말자.

참고 서적

스콧 마이어스, Effective Modern C++
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함