3 min read

type traits로 is_class 구현하기

C++에는 type traits라는게 있다.

이는 컴파일 타입에 타입의 traits을 알기위해 사용한다.

간단한 예로 같은 타입인지 구하기 위해서는 이렇게 작성했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct true_type {
enum {value  = true};
};
struct false_type {
enum { value = false };
};
template<typename T, typename U>
struct is_same : false_type {};
template<typename T>
struct is_same<T, T> : true_type {};
class A {
};
int main() {
std::cout << is_same<double,int>::value << std::endl;
std::cout << is_same<intint>::value << std::endl;
}
cs

위와 같이 타입의 특성을 참과 거짓으로 나누어 타입을 구별한다.

이떄 참과 거짓으로 말한 이유는 is_same을 보시면 전체의 범위에서 특정 타입을 측정 값을 구한다는 것이다.

그러면 class 구별은 어떻게 해야할까?

답은 http://en.cppreference.com에서 구할 수 있다.

해당 사이트에 Pointer declaration부분을 보면 S C::* D;라는 신기 한 문법이 있다.

이는 C타입의 멤버변수의 포인터를 선언 하는것이다.

이 특성을 이용해서 is_class를 구현을 간단히 할수 있다.

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
32
33
34
35
36
// ConsoleApplication4.cpp : Defines the entry point for the console application.
//
#include “stdafx.h”
#include <iostream>
#include <string>
#include <functional>
struct true_type {
    enum {value  = true};
};
struct false_type {
    enum { value = false };
};
template<typename T, typename = std::void_t<>>
struct is_class : false_type { };
template<typename T>
struct is_class<T, std::void_t<int T::*>> : true_type {};
template<typename T, typename U>
struct is_same : false_type {};
template<typename T>
struct is_same<T, T> : true_type {};
class A {
};
int main() {
    std::cout << is_class<A>::value << std::endl;
    std::cout << is_class<int>::value << std::endl;
}
cs

이를 실행 해보면 해당 타입이 클래스인지 아닌지 구분 할수 있게 해준다.

디폴트로 std::void_t를 넣은이유는 primary Type을 위해서 입니다.

Primary Type인 경우 std::void_t<int T::*> 를 처리할수 없으므로 void_t를 이용하여 디폴트 파라미터를 만들고 class인 경우 std::void_t<int T::*> 이 있으니 아래로 가게 됩니다.

C++ 17이후에는 ::value라는 접두사를 따로 안써도 되는 트릭이 존재합니다.

1
2
3
4
template <class T>
constexpr bool is_class_t = is_class<T>::value;
cs

코드는 이와 같습니다.