template <class T>
struct is_integral {
static const bool value = false;
};
template <>
struct is_integral<bool> {
static const bool value = true;
};
template <>
struct is_integral<char> {
static const bool value = true;
};
template <>
struct is_integral<char16_t> {
static const bool value = true;
};
이런 식으로 구현.
is_integral<type>::value
로 접근해서 true, false 확인할 수 있음template <bool Cond, class T = void>
struct enable_if {
};
template <class T>
struct enable_if<true, T> {
typedef T type;
};
enable_if<is_integral<T>, T>::type
이런 식으로 사용.false
이면 치환 오류가 발생해서 오버로딩 실패하게 되고true
이면 enable_if<true, T>
로 들어가서 enable_if<bool, T>::type
으로 접근해서 해당 템플릿 타입을 사용할 수 있게 한다.immediate context(함수 선언부라고 생각하면 될듯)
범위 내에서의 치환 오류는 컴파일 에러가 안 난다!ex)
explicit vector(
size_type n,
const value_type &val = value_type(),
const allocator_type &alloc = allocator_type())
: _allocator(alloc), _capacity(n), _size(n)
{
_data = _allocator.allocate(n);
for (int i = 0; i < n; i++)
_data[i] = val;
} // fill
template <class InputIterator>
vector(
typename ft::enable_if<!ft::is_integral<InputIterator>::value, InputIterator>::type first,
InputIterator last,
const allocator_type &alloc = allocator_type())
: _allocator(alloc), _capacity(last - first), _size(last - first)
{
_data = _allocator.allocate(_capacity);
for (InputIterator it = first; it != last; it++)
*(_data++) = *it;
} // range
fill constructor
와 range constructor
는 매개변수가 두 개이며 (enable_if를 사용하지 않은 경우) 타입 또한 같아질 수 있다. range constructor
가 템플릿 함수로 구현되어 있기 때문이다. vector(5,2)
는 fill constructor
로 value가 2이며 크기가 5인 vector를 생성하라는 뜻이지만 첫 번째 인자 5가 unsigned int가 아닌 signed int로 판단되고 fill constructor
를 지나 range constructor
로 일단 들어가 실행되게 된다.ft::is_integral
, ft::enable_if
를 이용한다.typename ft::enable_if<!ft::is_integral<InputIterator>::value, InputIterator>::type first
!ft::is_integral<InputIterator>::value
가 true가 돼서 range constructor
가 오버로딩 함수군에 포함되게 된다. 그렇지 않은 경우 Subsitution Failure
가 되어 오버로딩 함수군에서 제거 되고 fill constructor
가 올바르게 실행될 수 있다.