#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 라도 문제 없음
#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 규칙을 정확히 알고 사용해야 한다.