我天真地希望该程序可以编译并以成功状态运行:
#include <iterator>
#include <string>
int main()
{
const std::string s = "foo";
auto forward_iter = s.begin();
auto reverse_iter = std::make_reverse_iterator(forward_iter);
auto third_iter = std::make_reverse_iterator(reverse_iter);
return forward_iter != third_iter;
}
它无法编译,因为third_iter
的类型与我们开始时使用的forward_iter
的类型不同;而是reverse_iterator<reverse_iterator<normal_iterator>>
:
0.cpp:10:25: error: no match for ‘operator!=’ (operand types are ‘__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> >’ and ‘std::reverse_iterator<std::reverse_iterator<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > > >’)
return forward_iter != third_iter;
~~~~~~~~~~~~~^~~~~~~~~~~~~
重新阅读文档后,似乎std::make_reverse_iterator(it)
被指定为始终包装it
,即使it
已经是反向迭代器(并且在某种程度上讲得通,因为我们期望使用reverse_iterator
个成员(即base()
)。
在不知道我具有哪种类型的情况下,是否存在在普通(正向)迭代器和包装式(反向)迭代器之间交换的标准方法?还是我需要编写一个SFINAE函数对以适当地返回std::make_reverse_iterator(it)
和it.base()
?
答案 0 :(得分:2)
应该反转reverse_iterator给出原始类型的正向迭代器吗?
不。至少,这不是指定make_reverse_iterator
的方式。返回类型在标准中指定为reverse_iterator<Iterator>
。
在不知道我具有哪种类型的情况下,是否存在在普通(正向)迭代器和包装式(反向)迭代器之间交换的标准方法?
不。据我所知。
还是我需要编写一对SFINAE函数来适当地返回
std::make_reverse_iterator(it)
和it.base()
?
您可以编写它。我不能说你是否需要。
这里是一种实现方式:
#include <iterator>
#include <type_traits>
// https://stackoverflow.com/a/35408829/2079303
template<typename I>
struct is_reverse_iterator : std::false_type {};
template<typename I>
struct is_reverse_iterator<std::reverse_iterator<I>>
: std::integral_constant<bool, !is_reverse_iterator<I>::value> {};
template<class It>
auto
reverse_or_base(It&& i)
{
if constexpr (is_reverse_iterator<std::decay_t<It>>())
return i.base();
else
return std::make_reverse_iterator(std::forward<It>(i));
}
和测试:
#include <vector>
#include <cassert>
int main() {
std::vector<int> v;
static_assert(
std::is_same_v<
decltype(reverse_or_base(v.rbegin())),
std::vector<int>::iterator
>
);
assert(v.end() == reverse_or_base(v.rbegin()));
static_assert(
std::is_same_v<
decltype(reverse_or_base(v.begin())),
std::vector<int>::reverse_iterator
>
);
assert(v.rend() == reverse_or_base(v.begin()));
}
答案 1 :(得分:2)
我设法制作了一对小函数,以在正向和反向迭代器之间交换:
template<typename Iter>
auto toggle_iterator_direction(Iter it) {
return std::make_reverse_iterator(it);
}
template<typename Iter>
auto toggle_iterator_direction(std::reverse_iterator<Iter> it) {
return it.base();
}
以及以an answer to Determine if a (c++) iterator is reverse为模型的使用辅助类型模板的替代版本:
template<typename Iter>
struct is_reverse_iterator : std::false_type {};
template<typename Iter>
struct is_reverse_iterator<std::reverse_iterator<Iter>> : std::true_type {};
template<typename Iter>
auto toggle_iterator_direction(Iter it) {
if constexpr (is_reverse_iterator<Iter>())
return it.base();
else
return std::make_reverse_iterator(it);
}
这两个方法都可以修复修改后的测试程序:
#include <iterator>
#include <string>
int main()
{
const std::string s = "foo";
auto forward_iter = s.begin();
auto reverse_iter = toggle_iterator_direction(forward_iter);
auto third_iter = toggle_iterator_direction(reverse_iter);
return forward_iter != third_iter;
}