实际上,在C 14中,可以用很少的代码行完成 .
这与@Paul的解决方案非常相似 . 由于C 11中缺少的东西,该解决方案有点不必要地膨胀(加上std气味中的定义) . 多亏了C 14,我们可以让它更具可读性 .
关键的观察是基于范围的for循环依赖于 begin() 和 end() 来获取范围的迭代器 . 感谢ADL,甚至不需要在std :: namespace中定义自定义 begin() 和 end() .
这是一个非常简单的示例解决方案:
// -------------------------------------------------------------------
// --- Reversed iterable
template
struct reversion_wrapper { T& iterable; };
template
auto begin (reversion_wrapper w) { return std::rbegin(w.iterable); }
template
auto end (reversion_wrapper w) { return std::rend(w.iterable); }
template
reversion_wrapper reverse (T&& iterable) { return { iterable }; }
这就像一个魅力,例如:
template
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 { 1, 2, 3, 4, }));
// on const lvalue references
const list ints_list { 1, 2, 3, 4, };
for (auto&& el: reverse(ints_list))
cout << el << ',';
cout << '\n';
// on mutable lvalue references
vector 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,
NOTE std::rbegin() , std::rend() 和 std::make_reverse_iterator() 尚未在GCC-4.9中实施 . 我根据标准编写这些示例,但它们不会在稳定的g中编译 . 然而,为这三个函数添加临时存根非常容易 . 这是一个示例实现,绝对不完整,但在大多数情况下运行良好:
// --------------------------------------------------
template
reverse_iterator make_reverse_iterator (I i)
{
return std::reverse_iterator { i };
}
// --------------------------------------------------
template
auto rbegin (T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template
auto rend (T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
// const container variants
template
auto rbegin (const T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template
auto rend (const T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
UPDATE 22 Oct 2017
感谢estan指出这一点 .
原始答案示例实现使用 using namespace std; ,这将导致包含此实现(必须在头文件中)的任何文件也导入整个 std 命名空间 .
修改了示例实现以建议 using std::rbegin, std::rend .