说我需要使用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
?
答案 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
。这就是其他标准反向迭代器所做的事情。