TMP, SFINAE

42_Cursus·2022년 5월 17일
0

STL_Containers

목록 보기
6/13

TMP

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)

SFINAE

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에서 메타함수를 제공한다.

enable_if

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

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
profile
etudiant_42

0개의 댓글