iterator_traits

·2022년 12월 1일
0

iterator traits #1

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int n = sum( begin(s), end(s) );
    
    cout << n << endl; // 55
}

sum이 모든 타입의 반복자를 받을 수 있게 template 작성

#include <iostream>
#include <list>
using namespace std;

template<typename T>
void sum(T first, T last)
{
	// T는 반복자
    // T가 가리키는 타입이 필요함
    // auto s = *first; // C++11부터 auto 사용 가능
    // T::value_type // 반복자가 가리키는 타입
	typename T::value_type s = 0;
    
    while(first != last)
    {
    	s = s + *first;
        ++first;
    }
    
    return s;
}

int main()
{
	list<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int n = sum( begin(s), end(s) );
    
    cout << n << endl; // 55
}

(1) 반복자타입::value_type
반복자가 가리키는 요소의 타입

#include <iostream>
#include <list>
using namespace std;

template<typename T>
typename T::value_type sum(T first, T last)
{
	typename T::value_type s = 0;
    
    while(first != last)
    {
    	s = s + *first;
        ++first;
    }
    
    return s;
}

int main()
{
	// 가능 list<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    // 가능 vector<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int s[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //  컴파일 에러 발생
    
    int n = sum( begin(s), end(s) );
    
    cout << n << endl; // 55
}

(1) 반복자의 2가지 형태
- User Define Type으로 만들어진 반복자 : value_type이 있다.
- Raw Pointer : value_type이 없다.

문제점
Raw Pointer 안에는 "Member Type"이 없기 때문에 알고리즘 함수를 만들 때 문제가 생기게 된다.

#include <iostream>
#include <list>
#include <iterator>
using namespace std;

/*
template<typename T> struct iterator_traits
{
	using value_type = typename T::value_type;
};

// 핵심 : 포인터 버전을 부분 특수화
template<typename T> struct iterator_traits<T*>
{
	using value_type = T;
};
이미 존재하므로 #include <iterator> 헤더 추가
*/

template<typename T>
typename iterator_traits<T>::value_type sum(T first, T last)
{
	//typename T::value_type s = 0;
    
    typename iterator_traits<T>::value_type s = 0;
    
    while(first != last)
    {
    	s = s + *first;
        ++first;
    }
    
    return s;
}

int main()
{
	// list<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    // vector<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int s[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int n = sum( begin(s), end(s) );
    
    cout << n << endl; // 55
}

(1) iterator_traits
- Raw Pointer에는 "Member Type"이 없다는 문제를 해결하기 위한 도구
- 반복자의 value_type이 필요할 때, iterator_traits를 통해서 value_type을 사용한다.
(2) value_type을 사용하는 2가지 방식
-T::value_type : T가 Raw Pointer 라면 error
- iterator_traits::value_type : T가 Raw Pointer 라도 문제 없음

iterator traits #2

#include <iostream>
#include <list>
#inlcude <iterator>
using namespace std;
  
template<typename T> void foo(T a)
{
  	// T가 반복자 일 때 반복자가 가리키는 타입을 사용하고 싶다.
  	typename T::value_type n1; // error
  	typename iterator_traits<T>::value_type n2; // ok
}

template<typename T>
void eadvance_imp(T& p, int n, random_access_iterator_tag)
{
	p = p +n;
}
  
template<typename T>
void eadvance_imp(T& p, int n, input_iterator_tag)
{
  	while(n--) ++p;
}
  
template<typename T>
void eadvance(T& p, int n)
{
  	// eadvance_imp(p, n, typename T::iterator_category());
  	eadvance_imp(p, n, typename iterator_traits<T>::iterator_category());
}
  
int main()
{
  	// vector<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int s[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  
  	auto p = begin(s);
  	eadvance(p, 5);
  	cout << *p << endl;
}

#include <iostream>
#include <list>
#include <iterator>
using namespace std;
  
template<typename T>
typename iterator_traits<T>::value_type sum(T first, T last)
{
	//typename T::value_type s = 0;
    
    // typename iterator_traits<T>::value_type s = 0;
  
	// decltype(*first) s = 0; // 반복자가 가리키는 타입 -> error
  							   // decltype(*포인터타입) -> 참조 타입이 나옴
  
  	typename remove_reference<decltype(*first)>::type s = 0;
  	
    while(first != last)
    {
    	s = s + *first;
        ++first;
    }
    
    return s;
}

int main()
{
	// list<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    // vector<int> s = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int s[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
    int n = sum( begin(s), end(s) );
    
    cout << n << endl; // 55
}

(1) value_type 대신에 auto/decltype을 사용할 경우
- type deduction 규칙을 정확히 알고 사용해야 한다.

0개의 댓글