데이터 타입에 맞추어 동작을 시키는 것이 목적.
#include <type traits>
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 = #
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;
};
위와 같이 구현을 할 수 있다.
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 = #
// 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;
};
위와 같이 구현을 할 수 있다.
열거형에 주어진 타입을 사용한다.
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(bool, "message");
첫번째 인자인 bool의 값이 true인지 아닌지 확인을하는 함수이며 bool값이 false이면 컴파일 에러가 발생하며 2번째 인자인 message를 출력한다.
이를 이용해 특정 type을 판별할 수 있다.
// 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;
}
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