범위 기반 for-loop와 반대로 컨테이너를 반복 할 수 있도록 반복자의 방향을 바꾸는 컨테이너 어댑터가 있습니까?
명시 적 반복자를 사용하여 이것을 변환합니다.
for (auto i = c.begin(); i != c.end(); ++i) { ...
이것으로 :
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
이것을 변환하고 싶습니다 :
for (auto& i: c) { ...
이에:
for (auto& i: std::magic_reverse_adapter(c)) { ...
그런 것이 있습니까, 아니면 직접 써야합니까?
답변
실제로 Boost에는 다음과 같은 어댑터가 있습니다 boost::adaptors::reverse
.
#include <list>
#include <iostream>
#include <boost/range/adaptor/reversed.hpp>
int main()
{
std::list<int> x { 2, 3, 5, 7, 11, 13, 17, 19 };
for (auto i : boost::adaptors::reverse(x))
std::cout << i << '\n';
for (auto i : x)
std::cout << i << '\n';
}
답변
실제로 C ++ 14에서는 매우 적은 코드 줄로 수행 할 수 있습니다.
이것은 @Paul의 솔루션과 매우 유사합니다. C ++ 11에서 누락 된 것이 있기 때문에이 솔루션은 불필요하게 부풀어 오른 것입니다 (표준 냄새로 정의). C ++ 14 덕분에 훨씬 더 읽기 쉽게 만들 수 있습니다.
주요 관찰에 의존하여 그 범위 기반에 대한-루프 작품 begin()
과 end()
범위의 반복자를 얻기 위해. ADL 덕분에 사용자 정의 begin()
및 end()
std :: 네임 스페이스 를 정의 할 필요조차 없습니다 .
다음은 매우 간단한 샘플 솔루션입니다.
// -------------------------------------------------------------------
// --- Reversed iterable
template <typename T>
struct reversion_wrapper { T& iterable; };
template <typename T>
auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
template <typename T>
auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }
template <typename T>
reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }
이것은 예를 들어 매력처럼 작동합니다.
template <typename T>
void print_iterable (std::ostream& out, const T& iterable)
{
for (auto&& element: iterable)
out << element << ',';
out << '\n';
}
int main (int, char**)
{
using namespace std;
// on prvalues
print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, }));
// on const lvalue references
const list<int> ints_list { 1, 2, 3, 4, };
for (auto&& el: reverse(ints_list))
cout << el << ',';
cout << '\n';
// on mutable lvalue references
vector<int> ints_vec { 0, 0, 0, 0, };
size_t i = 0;
for (int& el: reverse(ints_vec))
el += i++;
print_iterable(cout, ints_vec);
print_iterable(cout, reverse(ints_vec));
return 0;
}
예상대로 인쇄
4,3,2,1,
4,3,2,1,
3,2,1,0,
0,1,2,3,
주 std::rbegin()
, std::rend()
그리고 std::make_reverse_iterator()
아직 GCC-4.9에서 구현되지 않습니다. 이 예제를 표준에 따라 작성하지만 안정적인 g ++로 컴파일하지는 않습니다. 그럼에도 불구하고이 세 가지 기능에 임시 스텁을 추가하는 것은 매우 쉽습니다. 다음은 샘플 구현입니다. 확실히 완료되지는 않았지만 대부분의 경우에는 잘 작동합니다.
// --------------------------------------------------
template <typename I>
reverse_iterator<I> make_reverse_iterator (I i)
{
return std::reverse_iterator<I> { i };
}
// --------------------------------------------------
template <typename T>
auto rbegin (T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
// const container variants
template <typename T>
auto rbegin (const T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (const T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
답변
이것은 부스트없이 C ++ 11에서 작동해야합니다.
namespace std {
template<class T>
T begin(std::pair<T, T> p)
{
return p.first;
}
template<class T>
T end(std::pair<T, T> p)
{
return p.second;
}
}
template<class Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
{
return std::reverse_iterator<Iterator>(it);
}
template<class Range>
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range&& r)
{
return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r)));
}
for(auto x: make_reverse_range(r))
{
...
}
답변
이것은 당신을 위해 작동합니까 :
#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>
int main(int argc, char* argv[]){
typedef std::list<int> Nums;
typedef Nums::iterator NumIt;
typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
typedef boost::iterator_range<NumIt> irange_1;
typedef boost::iterator_range<RevNumIt> irange_2;
Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );
// prints: 1 2 3 4 5 6 7 8
for(auto e : r1)
std::cout << e << ' ';
std::cout << std::endl;
// prints: 8 7 6 5 4 3 2 1
for(auto e : r2)
std::cout << e << ' ';
std::cout << std::endl;
return 0;
}
답변
template <typename C>
struct reverse_wrapper {
C & c_;
reverse_wrapper(C & c) : c_(c) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
};
template <typename C, size_t N>
struct reverse_wrapper< C[N] >{
C (&c_)[N];
reverse_wrapper( C(&c)[N] ) : c_(c) {}
typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};
template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
return reverse_wrapper<C>(c);
}
예 :
int main(int argc, const char * argv[]) {
std::vector<int> arr{1, 2, 3, 4, 5};
int arr1[] = {1, 2, 3, 4, 5};
for (auto i : r_wrap(arr)) {
printf("%d ", i);
}
printf("\n");
for (auto i : r_wrap(arr1)) {
printf("%d ", i);
}
printf("\n");
return 0;
}
답변
당신이 사용할 수있는 경우 범위 V3를 , 당신은 역 범위 어댑터를 사용할 수 있습니다 ranges::view::reverse
당신은 반대로 컨테이너를 볼 수 있습니다.
최소한의 실례 :
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main()
{
std::vector<int> intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto const& e : ranges::view::reverse(intVec)) {
std::cout << e << " ";
}
std::cout << std::endl;
for (auto const& e : intVec) {
std::cout << e << " ";
}
std::cout << std::endl;
}
데모 1을 참조하십시오 .
참고 : 바와 같이 당 에릭 Niebler ,이 기능에서 사용할 수 20 ++ C . <experimental/ranges/range>
헤더 와 함께 사용할 수 있습니다 . 그러면 for
진술은 다음과 같습니다.
for (auto const& e : view::reverse(intVec)) {
std::cout << e << " ";
}
데모 2 참조
답변
C ++ 14를 사용하지 않으면 가장 간단한 해결책을 아래에서 찾으십시오.
#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; }
template<typename T>
struct Reverse
{
T& m_T;
METHOD(begin());
METHOD(end());
METHOD(begin(), const);
METHOD(end(), const);
};
#undef METHOD
template<typename T>
Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }
데모 . 함수
가없는 컨테이너 / 데이터 유형 (예 : 배열)에는 begin/rbegin, end/rend
작동 하지 않습니다 .