이전에 enable_if
에 대해 설명을 하면서 is_integral
에 대해 잠시 언급했다.
https://velog.io/@jaekim/SFINE-%EC%99%80-enableif
간략히 정리하면... 템플릿의 제네릭 변수(T)에 어떤 자료형이 들어왔을 때, 컴파일러가 치환 할지 말지 결정하는 순간이 온다.
이때 is_integral 의 value 멤버가 true 인지 false 인지에 따라 결정했었다. (정확히는 is_integral 의 부모 클래스인 true_type(또는 false_type)의 value 멤버이다.)
아래 코드는 !
가 있기 때문에, true
가 반환되면 false
로 인식해서 치환하지 않는다.
template <typename T, typename std::enable_if<!std::is_integral<T>::value, T>::type* = nullptr>
T::value_type negative(const int& t) {
/* ... */
}
그렇다면 is_integral
은 어떻게 구현되어 있을까? 템플릿 함수가 false_type
과 true_type
클래스를 상속받는데, 특정 자료형으로 특수화가 됐고 각 자료형에 따라 상속 받는 bool
값이 다르다.
template <typename T>
struct is_integral : public false_type<false, void> {};
template <>
struct is_integral<bool> : public true_type<true, bool> {};
template <>
struct is_integral<char> : public true_type<true, char> {};
template <>
struct is_integral<long long> : public true_type<true, long long> {};
template <>
struct is_integral<unsigned long long>
: public true_type<true, unsigned long long> {};
true_type
과 false_type
은 다음처럼 되어있다.
template <bool is_integral, typename T>
struct true_type {
const static bool value = true;
typedef T type;
};
template <bool is_integral, typename T>
struct false_type {
const static bool value = false;
typedef T type;
};
각 클래스(true_type, false_type) 에는 value
멤버 변수를 갖고 있고 true_type::value
에는 true
, false_type::value
에는 false
값이 있다.
** 이 값은 특수화된 is_integral
함수에 들어오는 자료형에 따라 value
의 값이 달라진다.
예를 들어 위 코드를 바탕으로 다음과 같이 main 문을 만들어서 실행하자.
다음 결과가 나온다.
float 으로 특수화된 is_integral 은 없다. 그래서 디폴트 함수로 넘어가게 되며, 디폴트 함수는 false_type 클래스를 상속받았기 때문에 false, 즉 0을 반환한다.
그 외에 나머지는 true_type 클래스를 상속받아서 true, 즉 1 을 반환한다.