此解决方案不会引入不必要的副本,也不会像某些评论所建议的那样显示不正确的转发。说明如下。
您可以使用一些具有实际返回反向迭代器的开始和结束函数的包装器。
template<class T>
struct revert_wrapper
{
T o;
revert_wrapper(T&& i) : o(std::forward<T>(i)) {}
};
template<class T>
auto begin(revert_wrapper<T>& r)
{
using std::end;
return std::make_reverse_iterator(end(r.o));
}
template<class T>
auto end(revert_wrapper<T>& r)
{
using std::begin;
return std::make_reverse_iterator(begin(r.o));
}
template<class T>
auto begin(revert_wrapper<T> const& r)
{
using std::end;
return std::make_reverse_iterator(end(r.o));
}
template<class T>
auto end(revert_wrapper<T> const& r)
{
using std::begin;
return std::make_reverse_iterator(begin(r.o));
}
template<class T>
auto reverse(T&& ob)
{
return revert_wrapper<T>{ std::forward<T>(ob) };
}
像这样使用:
std::vector<int> v{1, 2, 3, 4};
for (auto i : reverse(v))
{
std::cout << i << "\n";
}
或者在你的情况下
for ( auto& i : reverse(lifo_stack) ) {
cout << "Current loop iteration has i = " << i << endl;
cout << "Popped an item from the stack: " << lifo_stack.pop() << endl;
}
由于转发不是一个简单的话题,并且存在误解,我将进一步解释一些细节。我将使用std::vector<int>
“待反转”类型作为示例T
。
1.功能模板reverse
。
1.1 传递左值std::vector<int>
:
std::vector<int> v{1, 2, 3, 4};
auto&& x = reverse(v);
在这种情况下,编译器创建的实例reverse
如下所示:
template<>
auto reverse<std::vector<int>&>(std::vector<int>& ob)
{
return revert_wrapper<std::vector<int>&>{ std::forward<std::vector<int>&>(ob) };
}
我们在这里看到两件事:
T
of revert_wrapper
will be ,因此std::vector<int>&
不涉及副本。
- 我们将左值作为左值转发给
revert_wrapper
1.2 传递右值std::vector<int>
std::vector<int> foo();
auto&& x = reverse(foo());
我们再看一下函数模板的实例化:
template<>
auto reverse<std::vector<int>>(std::vector<int>&& ob)
{
return revert_wrapper<std::vector<int>>{ std::forward<std::vector<int>>(ob) };
}
并且可以再次注意两件事:
- 的
T
将revert_wrapper
是std::vector<int>
,因此复制向量,防止右值在任何基于范围的循环可以运行之前超出范围
- 一个右值
std::vector<int>&&
将被转发到的构造函数revert_wrapper
2.类模板revert_wrapper
及其构造函数
2.1在左值的情况下revert_wrapper
创建者reverse
std::vector<int>&
template<>
struct revert_wrapper<std::vector<int>&>
{
std::vector<int>& o;
revert_wrapper(std::vector<int>& i) :
o(std::forward<std::vector<int>&>(i)) {}
};
如上所述:当我们存储参考时,不涉及副本。也似乎很熟悉,实际上它与上面的forward
相同reverse
:我们转发一个左值作为左值引用。
2.2在右值的情况下revert_wrapper
创建者reverse
std::vector<int>&&
template<>
struct revert_wrapper<std::vector<int>>
{
std::vector<int> o;
revert_wrapper(std::vector<int>&& i) :
o(std::forward<std::vector<int>>(i)) {}
};
这次我们将对象按值存储以防止悬空引用。转发也很好:我们将右值引用转发reverse
给revert_wrapper
构造函数,然后我们将它转发给std::vector
构造函数。我们可以static_cast<T&&>(i)
以相同的方式使用,但我们不是(std::)mov(e)
从左值 ing,我们正在转发:
我们还可以在这里看到另一件事:revert_wrapper
按值存储的实例的唯一可用构造函数采用右值。因此,我们不能(轻易地)欺骗这个类来制作不必要的副本。
请注意,在构造函数的初始化程序中std::forward
替换为实际上是错误的。std::move
o
revert_wrapper