Template Meta Programming.
사실은 함수는 아니지만, 마치 함수처럼 동작하는 템플릿 클래스들을 말한다.
이들이 메타함수인 이유는 보통의 함수들은 "값"에 대하여
연산을 수행하지만, 메타함수는 "타입"에 대해 연산을 수행한다.
ex)
#include <iostream>
#include <type_traits>
template <typename T>
void tell_type() {
if (std::is_void<T>::value) {
std::cout << "T est void! \n";
} else {
std::cout << "T est pas void! \n";
}
}
int main() {
tell_type<int>(); // pas de void!
tell_type<void>(); // void!
}
T est pas void!
T est void!
즉, tell_type<>()에서, ()에 값을 대입하는것이 아닌, <>에 타입을 대입하여 연산을 수행한다.
또한
TMP에서 "if"문은 템플릿 특수화를 통해서 구현된다.
if (std::is_void<T>::value)
Substitution failure is not an error
예)
#include <iostream>
template <typename T>
void test(typename T::x a) {
std::cout << "T::x \n";
}
template <typename T>
void test(typename T::y b) {
std::cout << "T::y \n";
}
struct A {
using x = int;
};
struct B {
using y = int;
};
int main() {
test<A>(33);
test<B>(22);
}
T::x
T::y
이 코드에서,
test<A>(33);
위에서, A를 템플릿인자로 전달하였다.
그렇다면,
template <typename T>
void test(typename T::x a) {
std::cout << "T::x \n";
}
template <typename T>
void test(typename T::y b) {
std::cout << "T::y \n";
}
에서 두 함수들은 각각 다음과 같이 치환된다.
void test(A::x a) { std::cout << "T::x \n"; }
void test(A::y b) { std::cout << "T::y \n"; }
여기서, " A::y "가 문법적으로 올바르지 않은 식이다.
(A클래스에 y라는 타입은 없다)
이런상황에서, 컴파일러는 "SFINAE"에 의하여, 컴파일 오류를 발생시키지않는다.
단지, 함수의 오버로딩 후보군에서 제외만 시킨다.
아, 그리고
다만, 함수내부적으로 파악하지못한다.
#include <iostream>
template <typename T>
void test(typename T::x a) {
typename T::y b; // 내부오류
}
template <typename T>
void test(typename T::y b) {
std::cout << "T::y \n";
}
struct A {
using x = int;
};
int main()
{
test<A>(11);
}
// compile error "typename T::y b;"
다음과같이 SFINAE를 활용한다면, 원하지 않는 타입에 대해서 오버로딩 후보군을 제외할수있다.
이런것을 위해서!
type_traits에서 메타함수를 제공한다.
SFINAE를 통해서 조건에 맞지않는 함수들을
오버로딩 후보군에서 쉽게 뺄수있게 도와주는
간단한 템플릿 메타 함수이다.
template<bool B, class T = void>
struct enable_if {};
template<class T>
struct enable_if<true, T> { typedef T type; };
#include <iostream>
#include <type_traits>
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() {
test(1); // int
test(false); // bool
test('c'); // char
}
t : 1
t : 0
t : c