[英]std::find() backwards on C-style array?
說我需要使用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
?
我不太確定我理解這個問題(這可能來自你似乎試圖避免的迭代器方向的尷尬混合),但我只是將你的注意力轉向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.count
為256
,則s.elements[s.count]
是未定義的行為,因為s.elements[s.count]
是*(s.elements + s.count)
,這是要取消引用的有效數組元素。
在實踐中,完整的表達式很好,因為&*x
取消了x
,但你仍然可能想要避免它:
some_slice(s.elements, s.elements + s.count);
s.elements[-1]
也可能是未定義的行為,但我認為嚴格來說它可能是合法的,因為你在數組之前有一個int
成員。
一個簡單的解決方案是編寫一個包裝器迭代器類來模擬反向迭代器,然后使用它而不是原始數組迭代器,像往常一樣使用std::find
。 所以當std::find
調用++it
,它會調用operator++
,它會在內部遞減實際的迭代器--rawIt
。 這就是其他標准反向迭代器所做的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.