【问题标题】:Should reversing a reverse_iterator give a forward iterator of the original type?反转reverse_iterator 是否应该提供原始类型的前向迭代器?
【发布时间】:2019-02-25 00:23:51
【问题描述】:

我天真地期望这个程序能够以成功的状态编译和运行:

#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&lt;reverse_iterator&lt;normal_iterator&gt;&gt;

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()

【问题讨论】:

  • 请提供您实际需要这种可能性的代码。
  • 您将不得不编写自己的 reverse_iterator 函数来交换它。 this 应该对此有所帮助。
  • @r3musn0x - 如果可以的话,我会坚持使用minimal reproducible example。无需使用太多代码来解决问题。总而言之,这是一个回文测试 - 一个传递正向和反向迭代器并使用 std::mismatch() 来查看以该点为中心的回文数的函数。我可以对参数进行更多限制,以便前向迭代器必须排在第一位(或最后一位)...
  • @Nathan 这就是我愿意听到的。我可能会这样做并写一个自我回答(如果有人创造了更好的技术,他们很清楚可以添加)。
  • @TobySpeight,只是不清楚为什么不能在需要时使用base()。当您不知道它是否已经反转时,您是否在上下文中使用std::make_reverse_iterator?我真的无法想象这个用例。

标签: c++ iterator reverse-iterator


【解决方案1】:

我设法制作了一对小函数来在正向和反向迭代器之间交换:

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;
}

【讨论】:

  • 我认为重载版本最好,因为它更简单。
  • 是的,这是我第二次写的。
【解决方案2】:

是否应该反转一个 reverse_iterator 给一个原始类型的前向迭代器?

没有。或者至少,make_reverse_iterator 不是这样指定的。返回类型在标准中指定为reverse_iterator&lt;Iterator&gt;

在不知道我有哪种类型的情况下,是否有一种标准方法可以在普通(正向)和包装(反向)迭代器之间进行交换?

没有。据我所知没有。

或者我是否需要编写一对 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()));
}

【讨论】:

    猜你喜欢
    • 2016-05-26
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-16
    • 2013-12-03
    • 2010-12-19
    相关资源
    最近更新 更多