实际上,在C ++ 14中,只需几行代码即可完成。
这在思想上与@Paul的解决方案非常相似。由于C ++ 11中缺少某些内容,因此该解决方案有点不必要地过大(加上在std气味中定义)。感谢C ++ 14,我们可以使它更具可读性。
关键的观察结果是,基于范围的for循环通过依赖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());
}