std :: find()向后在C风格数组? [英] std::find() backwards on C-style array?
问题描述
说我需要使用 s
:
typedef struct tagSOMESTRUCT //由别人定义C兼容
{
int count;
int elements [256];
} SOMESTRUCT;
SOMESTRUCT s;
并说我有一个函数:
模板< 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]);
其中(IMHO)由于一个错误而是丑陋的并且容易出错。 / p>
一方面,我不能简单地将 some_slice_rev
更改为 some_slice
使用(更好的)
some_slice(& s.elements [0],& s.elements [ s.count]);
因为 std :: find
另一方面,代码本身已经对我看起来很坏,因为我看不到 std :: find
会处理作为原始指针的反向迭代器。
在这种情况下修复代码的最好方法是什么?有没有办法使用反向迭代器是原始指针?或者是否有修复此问题的标准重构机制其他,而不是更改 SOMESTRUCT
?
我不太确定我理解这个问题(这可能是从笨拙的混合迭代器的方向,你似乎试图避免),但我会引导你的注意力 std :: reverse_iterator
:
#include< iostream>
#include< iterator>
//例如
模板< typename Iter>
void print_it(Iter first,Iter last)
{
std :: cout<< '|';
for(; first!= last; ++ first)
std :: cout<< ''<< *第一<< |;
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>
//例如
模板< typename Iter>
void print_it(Iter first,Iter last)
{
std :: cout< '|';
for(; first!= last; ++ first)
std :: cout<< ''<< *第一<< |;
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));
}
这:
模板< 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
成员。
Say I need to use s
:
typedef struct tagSOMESTRUCT // Defined by someone else; C-compatible
{
int count;
int elements[256];
} SOMESTRUCT;
SOMESTRUCT s;
and say I have a function like:
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);
}
In order to use this function, I need to say
some_slice_rev(&s.elements[s.count - 1], &s.elements[-1]);
which (IMHO) is ugly and error-prone due to the off-by-one errors.
On the one hand, I cannot simply change some_slice_rev
to some_slice
to use the (much better)
some_slice(&s.elements[0], &s.elements[s.count]);
because then std::find
would search from the beginning instead of the end.
On the other hand, the code itself already looks broken to me, because I can't see how std::find
would handle "reverse iterators" that are raw pointers.
What is the best way to fix the code in situations like this? Is there any way to work with reverse-iterators that are raw pointers? Or is there a standard refactoring mechanism for fixing this, other than changing SOMESTRUCT
?
I'm not quite sure I understand the question (that may be from the awkward mixing of iterator directions you seem to be trying to avoid), but I'll just direct your attention to 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));
}
They work like bi-directional iterators, except ++
is internally --
, and vice versa.
Note that it's a bit ugly. You might want some utility function:
#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));
}
So I think you want this:
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());
}
Relatively off-topic now, but note that s.elements[s.count]
is undefined behavior if s.count
is 256
, because s.elements[s.count]
is *(s.elements + s.count)
, which isn't a valid array element to dereference.
In practice, the full expression is fine because &*x
cancels out to x
, but you still probably want to avoid it:
some_slice(s.elements, s.elements + s.count);
s.elements[-1]
may also be undefined behavior, though I think strictly speaking it might be legal by accident, because you have an int
member before the array.
这篇关于std :: find()向后在C风格数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!