C++ 타입 - type traits

진경천·2023년 11월 3일
0

C++

목록 보기
72/90

type tratis

데이터 타입에 맞추어 동작을 시키는 것이 목적.

#include <type traits>

is_pointer

type이 포인터인지 아닌지를 bool 타입으로 나타내준다.
위와 마찬가지로 is_X<type>::value 는 value가 X가 맞는지 판별한다.

std::is_pointer<type>::value

data type은 bool이다.

예제

template<typename T>
void foo(T t) {
	cout << std::is_pointer<T>::value << endl;
}

int main() {
	int num = 0;
	int* pNum = &num;
	cout << std::boolalpha;
	foo(num);
	foo(pNum);
}
  • 실행 결과

    false
    true

template<typename T>
struct is_pointer {
	static const bool value = false;
};

template<typename T>
struct is_pointer<T*> {
	static const bool value = true;
};

위와 같이 구현을 할 수 있다.

add_pointer, remove_pointer

type에 포인터를 추가하거나 제거한다.

std::add_pointer<type>::type 변수
std::add_remove<type*>::type 변수

예제

int main() {
	cout << std::boolalpha;

	int num = 0;
	std::add_pointer<int>::type pNum = &num;
	// type으로써 작용함. (int* pNum = &num)
	*pNum = 10;
	cout << num << endl;
	std::remove_pointer<int*>::type num0 = 1;
	cout << num0 << endl;
	cout << "Pnum : " << typeid(pNum).name() << endl;
	cout << "num0 : " << typeid(num0).name() << endl;
}
  • 실행 결과

    10
    1
    Pnum : int * __ptr64
    num0 : int

template<typename T>
struct add_pointer {
	using type = T*;
};

template<typename T>
struct remove_pointer {
	using type = T;
};


template<typename T>
struct remove_pointer<T*> {
	using type = T;
};

위와 같이 구현을 할 수 있다.

underlying_type

열거형에 주어진 타입을 사용한다.

std::underlying_type<type>::type;

예제

enum Unscoped {
	A, B
};

enum class Scoped : long long {
	A, B = 100000000000
};

enum class Scoped1 {
	A = 200
};

int main() {
	cout << std::boolalpha;
	
	cout << static_cast<int>(Scoped::B) << endl;
	cout << static_cast<std::underlying_type<Scoped>::type>(Scoped::B) << endl;
}
  • 실행 결과

    1215752192
    100000000000

    static_cast에 int를 사용하면 overflow가 일어나고
    underlying_type을 사용하면 Scoped에 주어진 long long type이 사용된다.

template<typename T>
std::ostream& operator<<(std::ostream& os, const T& value) {
	using t = std::underlying_type<T>::type;
	cout << static_cast<t>(value);
	return cout;
}

int main() {
	cout << std::boolalpha;
	
	cout << Unscoped::A << endl;
	cout << Scoped::B << endl;
	cout << Scoped1::A << endl;
}

템플릿을 이용하여 사용하기 편리하게 구현할 수 있다.

  • 실행 결과

    0
    100000000000
    200

static_assert

static_assert(bool, "message");

첫번째 인자인 bool의 값이 true인지 아닌지 확인을하는 함수이며 bool값이 false이면 컴파일 에러가 발생하며 2번째 인자인 message를 출력한다.
이를 이용해 특정 type을 판별할 수 있다.

예제 (Scoped와 Unscoped 구분하기)

// Unscoped는 int형으로 전환이 되고 Scoped는 int형으로 전환이 안되는 특성을 이용
template<typename T>
struct is_scoped_enum {
	static const bool value = std::is_enum<T>::value && !std::is_convertible<T, int>::value;
};

template<typename T>
std::ostream& operator<<(std::ostream& os, const T& value) {
	static_assert(std::is_enum<T>::value, "T is not enum");
	using t = std::underlying_type<T>::type;
	cout << static_cast<t>(value);
	return cout;
}

enable_if

SFINAE 를 통해 조건에 맞지 않는 함수들을 오버로딩 후보군에서 쉽게 뺄 수 있게 도와주는 간단한 템플릿 메타 함수이다.

template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enale_if<true, T> { typedef T type; };

bool B가 참이라면 enable_if::type의 타입이 T가 되고 B가 거짓이라면 enable_if에 type이 존재하지 않게 된다.

예제

template <typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
void test(const T& t) {
	std::cout << "t : " << t << std::endl;
}

int main() {
	cout << std::boolalpha << endl;
    
	test(1);	// int
	test(false);	// bool
	test('c');	// char
}
  • 실행 결과

    t : 1
    t : false
    t : c

profile
어중이떠중이

0개의 댓글