namespace, enable_if

42_Cursus·2022년 5월 17일
2

STL_Containers

목록 보기
1/13

namespace

과제에서, 범위지정자앞에, 즉 네임스페이스는 ft라고 명시함.


#include <iostream>

namespace ft
{
	int i = 5;
}

int i = 4;

int	main(void)
{
	int i = 3;

	std::cout << i << std::endl;
	std::cout << ::i << std::endl;
	std::cout << ft::i << std::endl;
	return (0);
}

3
4
5

enable_if

우선적으로 왜 enable_if를 사용하는지 알아보자!

template<typename Iter>
void	test(Iter a, Iter b)
{
	// ...
}

이런 함수가 있다고 가정할때, 우리는 인자로서, iterator를 넣고싶기때문에, 함수 파라미터의 타입을 Iter로 정하였다.
하지만, 컴퓨터는 Iter를 int값으로 받아도, std::string으로 받아도, iterator를 받아도 구별하지못한다.

즉, enable_if를 이용하여, 받은 인자의 값이 정말로, iterator인지를 확인할수있다.


	template <class InputIterator>
			vector(
				InputIterator first,
				InputIterator last,
				const allocator_type& alloc = allocator_type(),
				typename ft::enable_if<!ft::is_integral<InputIterator>::value, InputIterator>::type* = 0)
			: m_size(0), m_capacity(0), m_alloc(alloc)
			{
				this->assign(first, last);
			}

다음은 벡터의 생성자중의 하나이다.
prototype은 다음과 같다.


template <class InputIterator>
         vector (InputIterator first, InputIterator last,
                 const allocator_type& alloc = allocator_type());

여기서 우리는 우선적으로, 제일 마지막에 위치한 파라미터만을 보기로한다.


typename ft::enable_if<!ft::is_integral<InputIterator>::value, InputIterator>::type* = 0

이것을 뜯어보자면, 우선은 enable_if 안에 위치한 is_integral을 볼수있다.
아래는, is_integral 구현부분이다.

// intergral type에 해당하는 자료형이 아닌경우 (특수화한 타입의 인자)
// false 출력
// true 일경우, SFINAE에 따라, 오버로딩후 type 생성
	template <typename T>
	struct is_integral {
		static const bool value = false;
	};

	// integral type에 해당하는 자료형 타입을 위한 템플릿 특수화
	template <> struct is_integral<bool> { static const bool value = true; };
	template <> struct is_integral<char> { static const bool value = true; };
	template <> struct is_integral<wchar_t> { static const bool value = true; };
	template <> struct is_integral<signed char> { static const bool value = true; };
	template <> struct is_integral<short int> { static const bool value = true; };
	template <> struct is_integral<int> { static const bool value = true; };
	template <> struct is_integral<long int> { static const bool value = true; };
	template <> struct is_integral<long long int> { static const bool value = true; };
	template <> struct is_integral<unsigned char> { static const bool value = true; };
	template <> struct is_integral<unsigned short int> { static const bool value = true; };
	template <> struct is_integral<unsigned int> { static const bool value = true; };
	template <> struct is_integral<unsigned long int> { static const bool value = true; };
	template <> struct is_integral<unsigned long long int> { static const bool value = true; };

위와같이, 타입변수가 false일경우에는 iterator로 볼수있다.
따라서,

!ft::is_integral<InputIterator>::value

이 부분은, iterator가 타입변수일때, false를 반환하고,
!와 연산되어, true가 된다.

다음은 enable_if이다.


	//	B가 true일때, type을 생성.
	//	아닐경우, 컴파일 하지않고, 오버로딩 대상을 찾음.

	// typename T = void
	// client code를 위한 더미 파라미터
	template <bool cond, typename T = void>
	struct enable_if {
	};

	template <typename T>
	struct enable_if<true, T> {
		typedef T type;
	};

enable_if의 첫번째 타입변수값이 true일때, type을 생성.

typename ft::enable_if<true, InputIterator>::type* = 0

타입을 생성한다는것은, 컴파일이 된다는것이고, 그렇다는것은 vector함수가 실행된다는것이다.

타입이 생성되지않는다면, 다른 후보군을 찾는다.

참고)
::type* = 0
부분에서, 0을 주는이유는, client code를 위해서이다.


int test(int a, float b = 0)
{
	std::cout << a * 2 << std::endl;
   	return (a * 2);
}

int main(void)
{
	test(2); // for client code == test(2, 0);
   	test(4, 4.2f); // possible
    return (0);
}
profile
etudiant_42

0개의 댓글