Notice
Recent Posts
Recent Comments
Link
- 책_곽용재님 홈페이지
- 책_노란북 - 책 가격비교
- 책_김재우-SICP번역
- 플밍_쏘쓰포지
- 플밍_CodingHorror ?
- 플밍_상킴
- 플밍_김민장님
- GPGStudy
- 플밍_미친감자님
- 플밍_jz
- 플밍_샤방샤방님
- 플밍_글쓰는프로그래머2
- 플밍_키보드후킹
- 사람_재혁
- 사람_kernel0
- 사람_박PD
- 사람_경석형
- 사람_nemo
- 사람_kikiwaka
- 사람_Junios
- 사람_harry
- 사람_어떤 개발자의 금서목록..
- 사람_모기소리
- 사람_낙타한마리
- 사람_redkuma
- 사람_영원의끝
- 사람_민식형
- 도스박스 다음카페
- 플레이웨어즈 - 게임하드웨어벤치마크
- http://puwazaza.com/
- David harvey의 Reading Marx's c…
- 씨네21
- 한겨레_임경선의 이기적인 상담실
- 본격2차대전만화 - 굽시니스트
- 영화_정성일 글모음 페이지
- 영화_영화속이데올로기파악하기
- 음식_생선회
- 죽력고
- 사람_한밀
- 플밍_수까락
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- stl
- 고전강의
- 정신분석
- 고등학교 사회공부
- programming challenges
- c++
- 진삼국무쌍5
- modernc++
- 게임
- 삼국지
- 정성일
- 유머
- 일리아스
- 프로그래밍
- 삼국지6
- 책
- template
- 소비자고발
- 단상
- 진중권
- 영화
- 유시민
- BSP
- 건강
- 김두식
- 태그가 아깝다
- 노무현
- 인문학
- 강유원
- Programming
Archives
- Today
- Total
01-05 13:01
lancelot.com
range library 본문
- range_for 를 이용해서 화면에 출력
#include<vector>
#include<iostream>
int main()
{
std::vector v = { 1,2,3,4,5 };
for (auto e : v)
std::cout << e << std::endl;
}
- 컨테이너의 일부만 출력할 수 있을까?
- container의 일부만 가리키는 take_view class
- 컨테이너(vector 등) 처럼 자원을 소유하지는 않음
- 이미 존재하는 컨테이너에 대한 새로운 뷰를 제공
#include<vector>
#include<iostream>
template<typename T>
class take_view
{
T& rng;
std::size_t count;
public :
take_view(T& r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
int main()
{
std::vector v = { 1,2,3,4,5 };
for (auto e : v)
std::cout << e << std::endl;
for(auto e : take_view{v, 3})
std::cout << e << std::endl;
}
- ranges::ref_view
#include<vector>
#include<iostream>
#include<ranges>
int main()
{
std::vector v1 = { 1,2,3 };
std::vector v2 = { 5,6,7,8,9 };
// std::vector<int>& r1=v1;
// std::vector<int>& r2=v2;
std::ranges::ref_view r1 = v1;
std::ranges::ref_view r2 = v2;
r1 = r2;
std::cout << v1.size() << std::endl;// 3
std::cout << v2.size() << std::endl;// 5
std::cout << r1.size() << std::endl;// 5
std::cout << r2.size() << std::endl;// 5
}
- std::ranges::ref_view
- 이동가능한 참조
- 포인터를 사용한 간단한 유틸리티
- C++11에 추가된 std::reference_wrapper 의 view 버전
- std::reference_wrapper
- C++ 에 추가된 이동가능한 참조.
- 구현 원리는 내부 멤버 포인터 사용
- 범용적인 용도
- std::ranges::ref_view
- reference_wrapper 의 컨테이너 버전
- begin(), end(), size(), empty(), data(), base() 등의 멤버함수 제공
#include<vector>
#include<iostream>
#include<ranges>
int main()
{
std::vector v1 = { 1,2,3 };
std::ranges::ref_view r1 = v1;
auto p1 = r1.begin();
auto p2 = r1.end();
std::cout << &v1 << std::endl;
std::cout << &r1.base() << std::endl;
}
- take_view 를 take_view 에 대입해보면, 참조가 가리키는 대상이 복제되어서 v1에 v2가 복제됨
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view
{
T& rng;
std::size_t count;
public:
take_view(T& r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
// 멤버에 &가 있으면( 여기서는 T& rng) operator= 를 제공해주지 않아서구현해야한다.
take_view& operator=(const take_view& tv)
{
if (&tv == this)
return *this;
rng = tv.rng;
count = tv.count;
return *this;
}
};
int main()
{
std::vector v1 = { 1,2,3 };
std::vector v2 = { 5,6,7,8,9 };
take_view tv1(v1, 2);
take_view tv2(v2, 3);
tv1 = tv2;
std::cout << v1.size() << std::endl;//5
std::cout << v2.size() << std::endl;//5
}
- tv 뷰를 가리키는 포인터만 옮기고 싶다면, take_view에 ref_view를 사용한다
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view
{
std::ranges::ref_view<T> rng;
std::size_t count;
public:
take_view(T& r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
int main()
{
std::vector v1 = { 1,2,3 };
std::vector v2 = { 5,6,7,8,9 };
take_view tv1(v1, 2);
take_view tv2(v2, 3);
tv1 = tv2;
std::cout << v1.size() << std::endl;// 3
std::cout << v2.size() << std::endl;// 5
}
- ref_view를 take_view와 reverse_view에 적용
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view
{
std::ranges::ref_view<T> rng;
std::size_t count;
public :
take_view(T& r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
template<typename T>
class reverse_view
{
std::ranges::ref_view<T> rng;
public:
reverse_view(T& r) : rng(r) {};
// ref_view 는 역반복자가 없기때문에 생성하는 make_reverse_iterator() 를 사용한다
auto begin() { return std::make_reverse_iterator(rng.end()); }
auto end() { return std::make_reverse_iterator(rng.begin()); }
};
int main()
{
std::vector v = { 1,2,3 };
for (auto e : reverse_view(v))
std::cout << e << std::endl;
std::ranges::ref_view r1(v);
// std::ranges::ref_view r2(std::vector<int>{1,2,3}); // error - ref_view는 내부적으로 포인터기때문에 임시객체(rvalue)를 받을 수 없다
}
- take_view(reverse_view) 중첩을 적용하면...
- 아래 take_view tv(reverse_view(v), 2) 에서 빌드가 안되야하는데... 왜 되지? VS2022, C++20 인데..-_-;
- 어쨌든 안되는 이유는 reverse_view(v)가 임시객체이기때문.
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view
{
std::ranges::ref_view<T> rng;
std::size_t count;
public :
take_view(T& r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
template<typename T>
class reverse_view
{
std::ranges::ref_view<T> rng;
public:
reverse_view(T& r) : rng(r) {};
auto begin() { return std::make_reverse_iterator(rng.end()); }
auto end() { return std::make_reverse_iterator(rng.begin()); }
};
int main()
{
std::vector v = { 1,2,3 };
reverse_view rv(v);
// take_view tv(rv, 2);
take_view tv(reverse_view(v), 2);
for (auto e : tv) //3, 2
std::cout << e << std::endl;
take_view tv1(v, 3); // ref_view<vector> 를 멤버로 포함
take_view tv2(rv, 3); // rev_view<reverse_view> 가 아니라
// rv(reverse_view) 의 복사본을 멤버로 포함했으면 좋겠다
}
- 그럼 임시객체로 하지말고, reverse_view(v) 처럼 들어오면, 복사본을 가지게 만들어보는 방법은?
- all 함수를 통해, 전달받은 컨테이너의 상태를 확인하고 다르게 반환해준다.
#include<vector>
#include<iostream>
#include<ranges>
// all 함수 안에서 ref_view 인지 아닌지 구분해보자
// 1. view class는 std::ranges::view_base에서 상속받는다
template<typename T>
class take_view : public std::ranges::view_base
{
std::ranges::ref_view<T> rng;
std::size_t count;
public :
take_view(T& r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
template<typename T>
auto all(T&& arg)
{
// T가 참조를 포함하고 있을수 있으니 참조를 제거한다
if constexpr (std::ranges::view<std::remove_cvref_t<T>>)
{
std::cout << "view" << std::endl;
//복사본 반환
return std::remove_cvref_t<T>(arg);
}
else
{
std::cout << "not view" << std::endl;
// vector => rev_view<vector>
return std::ranges::ref_view<std::remove_cvref_t<T>>(arg);
}
}
int main()
{
std::vector v = { 1,2,3 };
take_view tv(v, 2);
auto a1 = all(v);
auto a2 = all(tv);
std::cout << typeid(a1).name() << std::endl;
std::cout << typeid(a2).name() << std::endl;
}
- all이 표준에도 있으니, 이것을 take_view에 적용해보자
- rng 의 타입을 미리 정해두지말고, C++17부터 들어간 template deduction guide를 사용해서 정한다
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view : public std::ranges::view_base
{
T rng;
std::size_t count;
public :
take_view(T r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
// C++17 에 들어간 template deduction guide
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
take_view(T&& t, std::size_t)->take_view< std::views::all_t<T> >;
template<typename T>
class reverse_view : public std::ranges::view_base
{
T rng;
public:
reverse_view(T& r) : rng(r) {};
auto begin() { return std::make_reverse_iterator(rng.end()); }
auto end() { return std::make_reverse_iterator(rng.begin()); }
};
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
reverse_view(T&& t, std::size_t)->reverse_view< std::views::all_t<T> >;
int main()
{
std::vector v = { 1,2,3 };
reverse_view rv(v);
take_view tv1(v, 2);// 멤버로 ref_view<vector>
take_view tv2(rv, 2);// 멤버로 rev_view<reverse_view>가 아니라 reverse_view 복사본 포함
std::cout << typeid(tv1).name() << std::endl;
std::cout << typeid(tv2).name() << std::endl;
}
- view의 중첩을 실제로 사용해보자
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view : public std::ranges::view_base
{
T rng;
std::size_t count;
public :
take_view(T r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
// C++17 에 들어간 template deduction guide
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
take_view(T&& t, std::size_t)->take_view< std::views::all_t<T> >;
template<typename T>
class reverse_view : public std::ranges::view_base
{
T rng;
public:
reverse_view(T& r) : rng(r) {};
auto begin() { return std::make_reverse_iterator(rng.end()); }
auto end() { return std::make_reverse_iterator(rng.begin()); }
};
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
reverse_view(T&& t, std::size_t)->reverse_view< std::views::all_t<T> >;
int main()
{
std::vector v = { 1,2,3,4,5,6,7,8,9,10 };
reverse_view rv(v);
take_view tv(rv, 3);
for(auto e : tv)
std::cout << e << std::endl;
for (auto e : take_view(reverse_view(v), 3) )
std::cout << e << std::endl;
}
- view 의 각종 함수들을 모아둔 view_interface를 구현
- CRTP 테크닉을 사용
#include<vector>
#include<iostream>
#include<ranges>
// view interface : view 에 필요한 함수들을 모아둠
template<typename T>
class view_interface : public std::ranges::view_base
{
T& Cast() { return static_cast<T&>(*this); }
public :
// int size() { return this->end() - this->begin(); }
// int size() { return static_cast<take_view*>(this)->end() - static_cast<take_view*>(this)->begin(); }
// int size() { return static_cast<T*>(this)->end() - static_cast<T*>(this)->begin(); }
size_t size() { return Cast().end() - Cast().begin(); }
};
template<typename T>
class take_view : public view_interface<take_view<T>>
{
T rng;
std::size_t count;
public :
take_view(T r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
// C++17 에 들어간 template deduction guide
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
take_view(T&& t, std::size_t)->take_view< std::views::all_t<T> >;
template<typename T>
class reverse_view : public view_interface<reverse_view<T>>
{
T rng;
public:
reverse_view(T& r) : rng(r) {};
auto begin() { return std::make_reverse_iterator(rng.end()); }
auto end() { return std::make_reverse_iterator(rng.begin()); }
};
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
reverse_view(T&& t, std::size_t)->reverse_view< std::views::all_t<T> >;
int main()
{
std::vector v = { 1,2,3,4,5,6,7,8,9,10 };
take_view tv(v, 3);
std::cout << v.size() << std::endl; // 10
std::cout << tv.size() << std::endl;// 3
reverse_view rv(v);
std::cout << rv.size() << std::endl;// 10
}
- C++20 의 표준에 제공되는 view_interface 를 사용해보자
#include<vector>
#include<iostream>
#include<ranges>
template<typename T>
class take_view : public std::ranges::view_interface<take_view<T>>
{
T rng;
std::size_t count;
public :
take_view(T r, std::size_t c) : rng(r), count(c) {};
auto begin() { return rng.begin(); }
auto end() { return rng.begin() + count; }
};
// C++17 에 들어간 template deduction guide
template<typename T>
//take_view(T&& t, std::size_t)->take_view< std::remove_cvref_t<decltype(std::views::all(t))> >;
take_view(T&& t, std::size_t)->take_view< std::views::all_t<T> >;
int main()
{
std::vector v = { 1,2,3,4,5,6,7,8,9,10 };
take_view tv(v, 3);
std::cout << v.size() << std::endl;
std::cout << tv.empty() << std::endl;
std::cout << tv.data() << std::endl;
}