std :: find()向后转C风格的数组?

时间:2012-03-24 08:12:51

标签: c++ pointers iterator find

说我需要使用s

typedef struct tagSOMESTRUCT   // Defined by someone else; C-compatible
{
    int count;
    int elements[256];
} SOMESTRUCT;

SOMESTRUCT s;

并说我的功能如下:

template<typename RevFwdIt>
std::pair<RevFwdIt, RevFwdIt> some_slice_rev(RevFwdIt rbegin, RevFwdIt rend)
{
    RevFwdIt it = basename_rev(rbegin, rend);
    RevFwdIt e = std::find(rbegin, it, 5);
    return std::make_pair(e == it ? rbegin : e, it);
}

为了使用这个功能,我需要说

some_slice_rev(&s.elements[s.count - 1], &s.elements[-1]);

其中(恕我直言)由于出现错误而导致丑陋且容易出错。

一方面,我不能简单地将some_slice_rev更改为some_slice以使用(更好)

some_slice(&s.elements[0], &s.elements[s.count]);

因为std::find会从头开始而不是结束搜索。

另一方面,代码本身对我来说已经坏了,因为我看不出std::find如何处理作为原始指针的“反向迭代器”。

在这种情况下修复代码的最佳方法是什么?有没有办法使用作为原始指针的反向迭代器?或者是否有一个标准的重构机制来解决这个问题,其他而不是更改SOMESTRUCT

2 个答案:

答案 0 :(得分:7)

我不太确定我理解这个问题(可能是因为您似乎试图避免使用迭代器方向的尴尬混合),但我只会将您的注意力转移到std::reverse_iterator

#include <iostream>
#include <iterator>

// for example
template <typename Iter>
void print_it(Iter first, Iter last)
{
    std::cout << '|';

    for (; first != last; ++first)
        std::cout << ' ' << *first << " |";

    std::cout << std::endl;
}

int main()
{
    int arr[10] = {1, 2, 3, 4};

    int *begin = arr, *end = arr + 4;

    print_it(begin, end);
    print_it(std::reverse_iterator<int*>(end),
                std::reverse_iterator<int*>(begin));
}

它们的工作方式类似于双向迭代器,除了++在内部--,反之亦然。

请注意,它有点难看。您可能需要一些效用函数:

#include <iostream>
#include <iterator>

// for example
template <typename Iter>
void print_it(Iter first, Iter last)
{
    std::cout << '|';

    for (; first != last; ++first)
        std::cout << ' ' << *first << " |";

    std::cout << std::endl;
}

template <typename Iter>
std::reverse_iterator<Iter> make_reverse_iterator(Iter iter)
{
    return std::reverse_iterator<Iter>(iter);
}

int main()
{
    int arr[10] = {1, 2, 3, 4};

    int *begin = arr, *end = arr + 4;

    print_it(begin, end);
    print_it(make_reverse_iterator(end),
                make_reverse_iterator(begin));
}

所以我想你想要这个:

template<typename ForwardIterator >
std::pair<ForwardIterator, ForwardIterator>
    some_slice(ForwardIterator begin, ForwardIterator end)
{
    typedef std::reverse_iterator<ForwardIterator> rev_iter;

    rev_iter it = basename(rev_iter(end), rev_iter(begin));
    rev_iter e = std::find(rev_iter(end), it, 5);

    return std::make_pair(it.base(), e.base());
}

现在相对偏离主题,但请注意,如果s.elements[s.count]s.count,则256是未定义的行为,因为s.elements[s.count]*(s.elements + s.count),而不是&*x一个有效的数组元素,用于解除引用。

在实践中,完整表达式很好,因为x取消了some_slice(s.elements, s.elements + s.count); ,但您仍可能想要避免它:

s.elements[-1]

int也可能是未定义的行为,但我认为严格来说这可能是合法的,因为你在数组之前有一个{{1}}成员。

答案 1 :(得分:1)

一个简单的解决方案是编写一个包装器迭代器类来模拟反向迭代器,然后像往常一样使用它来代替原始数组迭代器std::find。因此,当std::find调用++it时,它会调用operator++,它会在内部递减实际的迭代器--rawIt。这就是其他标准反向迭代器所做的事情。