본문 바로가기
NC University/Advanced C++

2일차 - Int2Type & integral_constant

by 날쑤 2015. 7. 1.

Int2Type

  이전 글에서 같은 타입의 인자 두 개를 받아서 큰 값을 반환하는 Max 함수의 구현을 완전히 마무리짓지 못하고 넘어갔었다. 그 때 구현 방식은 표준의 is_pointer<T> type-trait를 이용해서 인자가 포인터 타입일 경우에는 역참조를 해서 비교하고, 값일 경우에는 그냥 비교를 해서 값을 반환하도록 했다. 이는 아래와 같은 코드가 된다.

#include <type_traits>

template <typename T>
T Max (T a, T b)
{
  if (std::is_pointer<T>::value == true)
  {
    return *a < *b ? b : a; 
  }
  return a < b ? b : a;
}

  하지만 위의 함수는 값 타입 변수 두 개를 넘겼을 때 컴파일이 되지 않는다. 이는 위의 함수에서 T가 값 타입이더라도 역참조 하는 부분 자체는 컴파일 과정에 포함되기 때문이다. 이 문제를 해결하기 위해 우선 다음과 같은 템플릿을 정의하자.

// 컴파일 타임에 결정되는 상수값을 타입으로 변환
template <int N> struct Int2Type
{
  enum { value = N };
};

  이 템플릿을 이용하면 0과 1은 정수형으로 같은 타입이지만, Int2Type<0>과 Int2Type<1>은 다른 타입이 된다. 이제 여기에 함수 오버로딩을 끼얹어보자.

#include <type_traits>

template <typename T>
inline T MaxImpl (T a, T b, Int2Type<1>)
{
  return *a < *b ? b : a; 
}

template <typename T>
inline T MaxImpl (T a, T b, Int2Type<0>)
{
  return a < b ? b : a;
}

template <typename T>
T Max (T a, T b)
{
  return MaxImpl(a, b, Int2Type<std::is_pointer<T>::value>());
}

  위의 수정된 코드에서는 인자가 포인터 타입이 아닐 경우에는 두 번째 MaxImpl만 사용되고, 사용되지 않는 첫 번째 MaxImpl은 함수 템플릿의 특성상 아예 컴파일에 포함 자체가 되지 않는다. 그러므로 이제는 Max 함수가 T의 포인터 여부에 관계없이 의도대로 동작하게 되었다.
  그리고 내부에서 호출하는 MaxImpl은 inline 치환시켜서 목적 코드 사이즈는 비슷하게 유지하면서 함수 호출 오버헤드는 발생하지 않도록 하였다. inline 치환이 가능한 것은 함수 오버로딩에서 어떤 함수가 호출될지는 컴파일 타임에 결정되며, 컴파일 타임에 호출 여부가 결정되는 inline 함수는 치환이 가능하기 때문이다.

integral constant

  C++ 표준위원회는 위에서 다룬 Int2Type을 발전시켜서 아래와 같은 템플릿을 표준에 추가하였다.

template <typename T, T N>
struct integral_constant
{
  static const T value = N; //< enum 대신 static const를 사용
};

typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

  true와 false는 참 또는 거짓을 나타내는 서로 다른 값이지만, 같은 타입(bool)이다. 반면에 true_type과 false_type은 참/거짓을 나타낼 수 있는 서로 다른 '타입'이다. Int2Type<0>과 Int2Type<1>이 다른 타입인 것 처럼 말이다. 또한 표준에서는 이를 바탕으로 많은 type-trait들을 정의하고 있다. 지금까지 많이 언급했었던 std::is_pointer의 구현은 대충 다음과 같은 식이다.

template <typename T> 
struct is_pointer : false_type
{};

template <typename T>
struct is_pointer<T*> : true_type
{};

'NC University > Advanced C++' 카테고리의 다른 글

3일차 - 임시객체 & 예외안정성  (0) 2015.07.07
3일차 - 멤버함수 포인터  (0) 2015.07.03
2일차 - Template 부분 전문화(2)  (0) 2015.06.30
2일차 - 템플릿 인자  (0) 2015.06.30
2일차 - value_type  (0) 2015.06.29